Lint: Whole codebase with black
This commit is contained in:
parent
3ab48fab3a
commit
76925684c7
124
albero/app.py
124
albero/app.py
@ -12,26 +12,28 @@ from pprint import pprint
|
||||
from albero.query import Query
|
||||
from albero.utils import schema_validate
|
||||
import anyconfig
|
||||
|
||||
# from box import Box
|
||||
from pathlib import Path
|
||||
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class App():
|
||||
class App:
|
||||
|
||||
schema = {
|
||||
"$schema": 'http://json-schema.org/draft-07/schema#',
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
"default": {},
|
||||
"$def" :{
|
||||
'backends_items': {},
|
||||
'backends_config': {},
|
||||
'rules_items': {},
|
||||
'rules_config': {},
|
||||
},
|
||||
"$def": {
|
||||
"backends_items": {},
|
||||
"backends_config": {},
|
||||
"rules_items": {},
|
||||
"rules_config": {},
|
||||
},
|
||||
"patternProperties": {
|
||||
".*": {
|
||||
"type": "object",
|
||||
@ -39,53 +41,51 @@ class App():
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
"config": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
"app": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
"root": {
|
||||
"type": "string",
|
||||
"default": None,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"tree": {
|
||||
#"additionalProperties": False,
|
||||
"type": "object",
|
||||
"default": {},
|
||||
},
|
||||
"rules": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
},
|
||||
},
|
||||
|
||||
},
|
||||
"tree": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
"app": {
|
||||
"type": "object",
|
||||
"properties": { "$ref": "#/$defs/backends_items" },
|
||||
"default": {},
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
"root": {
|
||||
"type": "string",
|
||||
"default": None,
|
||||
},
|
||||
},
|
||||
},
|
||||
"rules": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
# "arrayItem": { "$ref": "#/$defs/rules_items" },
|
||||
},
|
||||
"tree": {
|
||||
# "additionalProperties": False,
|
||||
"type": "object",
|
||||
"default": {},
|
||||
},
|
||||
"rules": {
|
||||
"type": "object",
|
||||
"default": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
"tree": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {"$ref": "#/$defs/backends_items"},
|
||||
},
|
||||
},
|
||||
"rules": {
|
||||
"type": "array",
|
||||
"default": [],
|
||||
# "arrayItem": { "$ref": "#/$defs/rules_items" },
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, config="albero.yml", namespace='default'):
|
||||
def __init__(self, config="albero.yml", namespace="default"):
|
||||
conf2 = anyconfig.load(config)
|
||||
|
||||
# Validate configuration
|
||||
@ -93,27 +93,26 @@ class App():
|
||||
try:
|
||||
conf2 = conf2[namespace]
|
||||
except KeyError:
|
||||
log.error (f"Can't find namespace '{namespace}' in config '{config}'")
|
||||
log.error(f"Can't find namespace '{namespace}' in config '{config}'")
|
||||
sys.exit(1)
|
||||
|
||||
# Init
|
||||
if not conf2['config']['app']['root']:
|
||||
conf2['config']['app']['root'] = Path(config).parent
|
||||
if not conf2["config"]["app"]["root"]:
|
||||
conf2["config"]["app"]["root"] = Path(config).parent
|
||||
else:
|
||||
conf2['config']['app']['root'] = Path(conf2['config']['app']['root'])
|
||||
conf2["config"]["app"]["root"] = Path(conf2["config"]["app"]["root"])
|
||||
|
||||
# Finish
|
||||
self.conf2 = dict(conf2)
|
||||
|
||||
def lookup(self, key=None, policy=None, scope=None, trace=False, explain=False):
|
||||
log.debug(f"Lookup key {key} with scope: {scope}")
|
||||
q = Query(app = self)
|
||||
r = q.exec(key=key, scope=scope , policy=policy, trace=trace, explain=explain)
|
||||
|
||||
print ("=== Query Result ===")
|
||||
print(anyconfig.dumps(r, ac_parser='yaml'))
|
||||
print ("=== Query Result ===")
|
||||
q = Query(app=self)
|
||||
r = q.exec(key=key, scope=scope, policy=policy, trace=trace, explain=explain)
|
||||
|
||||
print("=== Query Result ===")
|
||||
print(anyconfig.dumps(r, ac_parser="yaml"))
|
||||
print("=== Query Result ===")
|
||||
|
||||
def dump_schema(self):
|
||||
|
||||
@ -125,10 +124,7 @@ class App():
|
||||
r2 = RulesManager.get_schema(AlberoPlugins)
|
||||
|
||||
d = self.schema
|
||||
d['patternProperties']['.*']['properties'] ['tree']['items']['properties'] = r1
|
||||
d['patternProperties']['.*']['properties'] ['tree']['items'] = r2
|
||||
d["patternProperties"][".*"]["properties"]["tree"]["items"]["properties"] = r1
|
||||
d["patternProperties"][".*"]["properties"]["tree"]["items"] = r2
|
||||
|
||||
print(json.dumps(d, indent=2))
|
||||
|
||||
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ sys.path.append("/home/jez/prj/bell/training/tiger-ansible/ext/ansible-tree")
|
||||
|
||||
import albero.app as Albero
|
||||
|
||||
|
||||
class CmdApp:
|
||||
"""Main CmdApp"""
|
||||
|
||||
@ -99,7 +100,9 @@ class CmdApp:
|
||||
"""Prepare command line"""
|
||||
|
||||
# Manage main parser
|
||||
parser = argparse.ArgumentParser(description="Albero, to lookup hierarchical data")
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Albero, to lookup hierarchical data"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", "--verbose", action="count", default=0, help="Increase verbosity"
|
||||
)
|
||||
@ -112,13 +115,19 @@ class CmdApp:
|
||||
|
||||
# Manage command: demo
|
||||
add_p = subparsers.add_parser("lookup")
|
||||
add_p.add_argument("-n", "--namespace", help="Namespace name", default='default')
|
||||
add_p.add_argument("-f", "--file", help="File with params as dict. Can be stdin - .")
|
||||
add_p.add_argument("-e", "--scope", dest="scope_param", action="append", default=[])
|
||||
add_p.add_argument(
|
||||
"-n", "--namespace", help="Namespace name", default="default"
|
||||
)
|
||||
add_p.add_argument(
|
||||
"-f", "--file", help="File with params as dict. Can be stdin - ."
|
||||
)
|
||||
add_p.add_argument(
|
||||
"-e", "--scope", dest="scope_param", action="append", default=[]
|
||||
)
|
||||
add_p.add_argument("-p", "--policy")
|
||||
add_p.add_argument("-t", "--trace", action="store_true")
|
||||
add_p.add_argument("-x", "--explain", action="store_true")
|
||||
add_p.add_argument("key", default=None, nargs="*")
|
||||
add_p.add_argument("key", default=None, nargs="*")
|
||||
|
||||
# Manage command: demo
|
||||
add_p = subparsers.add_parser("demo")
|
||||
@ -150,9 +159,9 @@ class CmdApp:
|
||||
def cli_lookup(self):
|
||||
"""Display how to use logging"""
|
||||
|
||||
config = '/home/jez/prj/bell/training/tiger-ansible/tree.yml'
|
||||
config = "/home/jez/prj/bell/training/tiger-ansible/tree.yml"
|
||||
|
||||
# self.log.debug(f"Command line vars: {vars(self.args)}")
|
||||
# self.log.debug(f"Command line vars: {vars(self.args)}")
|
||||
keys = self.args.key or [None]
|
||||
|
||||
# Parse payload from enf file:
|
||||
@ -162,7 +171,7 @@ class CmdApp:
|
||||
|
||||
# Parse cli params
|
||||
for i in self.args.scope_param:
|
||||
r = i.split('=')
|
||||
r = i.split("=")
|
||||
if len(r) != 2:
|
||||
raise Exception("Malformed params")
|
||||
new_params[r[0]] = r[1]
|
||||
@ -171,18 +180,19 @@ class CmdApp:
|
||||
|
||||
app = Albero.App(config=config, namespace=self.args.namespace)
|
||||
for key in keys:
|
||||
app.lookup(key=key,
|
||||
scope=new_params,
|
||||
trace=self.args.trace,
|
||||
explain=self.args.explain
|
||||
)
|
||||
app.lookup(
|
||||
key=key,
|
||||
scope=new_params,
|
||||
trace=self.args.trace,
|
||||
explain=self.args.explain,
|
||||
)
|
||||
|
||||
def cli_schema(self):
|
||||
"""Display configuration schema"""
|
||||
|
||||
config = '/home/jez/prj/bell/training/tiger-ansible/tree.yml'
|
||||
config = "/home/jez/prj/bell/training/tiger-ansible/tree.yml"
|
||||
|
||||
app = Albero.App(config=config) #, namespace=self.args.namespace)
|
||||
app = Albero.App(config=config) # , namespace=self.args.namespace)
|
||||
app.dump_schema()
|
||||
|
||||
|
||||
|
||||
@ -1,33 +1,22 @@
|
||||
|
||||
import dpath.util
|
||||
|
||||
import copy
|
||||
import json
|
||||
import textwrap
|
||||
from prettytable import PrettyTable
|
||||
from pathlib import Path
|
||||
# from box import Box
|
||||
from jsonmerge import Merger
|
||||
import re
|
||||
import logging
|
||||
from pprint import pprint
|
||||
import collections
|
||||
|
||||
|
||||
from albero.utils import schema_validate, str_ellipsis
|
||||
from albero.utils import schema_validate
|
||||
import albero.plugin as AlberoPlugins
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LoadPlugin():
|
||||
|
||||
class LoadPlugin:
|
||||
def __init__(self, plugins):
|
||||
self.plugins = plugins
|
||||
|
||||
def load(self, kind, name):
|
||||
|
||||
assert (isinstance(name, str)), f"Got: {name}"
|
||||
assert isinstance(name, str), f"Got: {name}"
|
||||
|
||||
# Get plugin kind
|
||||
try:
|
||||
@ -41,18 +30,25 @@ class LoadPlugin():
|
||||
except Exception as e:
|
||||
raise Exception(f"Unknown module '{kind}.{name}': {e}")
|
||||
|
||||
assert (hasattr(plugin_cls, 'Plugin')), f'Plugin {kind}/{name} is not a valid plugin'
|
||||
assert hasattr(
|
||||
plugin_cls, "Plugin"
|
||||
), f"Plugin {kind}/{name} is not a valid plugin"
|
||||
|
||||
# Return plugin Classe
|
||||
return plugin_cls.Plugin
|
||||
|
||||
class Manager():
|
||||
|
||||
class Manager:
|
||||
"""Generic manager class"""
|
||||
|
||||
plugins_kind = []
|
||||
_schema_props_default = None
|
||||
_schema_props_new = None
|
||||
_props_position = None
|
||||
|
||||
@classmethod
|
||||
def get_schema(cls, plugins_db):
|
||||
"""Retrieve configuration schema"""
|
||||
|
||||
# Properties
|
||||
ret3 = {}
|
||||
@ -60,15 +56,17 @@ class Manager():
|
||||
# ret[kind] = {}
|
||||
plugin_kind = getattr(plugins_db, kind)
|
||||
|
||||
for plugin_name in [i for i in dir(plugin_kind) if not i.startswith('_')]:
|
||||
for plugin_name in [i for i in dir(plugin_kind) if not i.startswith("_")]:
|
||||
plugin = getattr(plugin_kind, plugin_name)
|
||||
plugin_cls = getattr(plugin, 'Plugin', None)
|
||||
plugin_cls = getattr(plugin, "Plugin", None)
|
||||
if plugin_cls:
|
||||
schema_props = getattr(plugin_cls, '_schema_props_new', 'MISSING ITEM')
|
||||
schema_props = getattr(
|
||||
plugin_cls, "_schema_props_new", "MISSING ITEM"
|
||||
)
|
||||
if schema_props:
|
||||
# ret[kind][plugin_name] = schema_props
|
||||
ret3.update( schema_props )
|
||||
ret3.update( cls._schema_props_new )
|
||||
ret3.update(schema_props)
|
||||
ret3.update(cls._schema_props_new)
|
||||
|
||||
# Injection
|
||||
ret1 = cls._schema_props_default
|
||||
@ -79,76 +77,76 @@ class Manager():
|
||||
|
||||
|
||||
class BackendsManager(Manager):
|
||||
"""Backend Manager"""
|
||||
|
||||
plugins_kind = ['engine', 'backend']
|
||||
plugins_kind = ["engine", "backend"]
|
||||
|
||||
_schema_props_new = {
|
||||
"engine": {
|
||||
"type": "string",
|
||||
"default": "jerakia",
|
||||
"optional": False,
|
||||
},
|
||||
"value": {
|
||||
"default": 'UNSET',
|
||||
"optional": False,
|
||||
},
|
||||
}
|
||||
"engine": {
|
||||
"type": "string",
|
||||
"default": "jerakia",
|
||||
"optional": False,
|
||||
},
|
||||
"value": {
|
||||
"default": "UNSET",
|
||||
"optional": False,
|
||||
},
|
||||
}
|
||||
|
||||
_props_position = 'oneOf/0/properties'
|
||||
_props_position = "oneOf/0/properties"
|
||||
_schema_props_default = {
|
||||
"$schema": 'http://json-schema.org/draft-07/schema#',
|
||||
"default": "",
|
||||
# This does not work :(
|
||||
#"$def": {
|
||||
# "props": {},
|
||||
# },
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": True,
|
||||
"default": {},
|
||||
"title": "object",
|
||||
"properties": {},
|
||||
"description": "Object to configure a bacjend item",
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "BLAAAAHHH",
|
||||
"title": "string",
|
||||
"description": "Enter a simple string configuration value for default engine",
|
||||
},
|
||||
]
|
||||
}
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"default": "",
|
||||
# This does not work :(
|
||||
# "$def": {
|
||||
# "props": {},
|
||||
# },
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": True,
|
||||
"default": {},
|
||||
"title": "object",
|
||||
"properties": {},
|
||||
"description": "Object to configure a bacjend item",
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "BLAAAAHHH",
|
||||
"title": "string",
|
||||
"description": "Enter a simple string configuration value for default engine",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
def _validate_item(self, item):
|
||||
"""Private method to validate sub class"""
|
||||
if isinstance(item, str):
|
||||
item = {
|
||||
"engine": self.config_main.default_engine,
|
||||
"value": item,
|
||||
}
|
||||
"engine": self.config_main.default_engine,
|
||||
"value": item,
|
||||
}
|
||||
item = schema_validate(item, self._schema_props_default)
|
||||
assert (isinstance(item, dict))
|
||||
assert isinstance(item, dict)
|
||||
return item
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
|
||||
self.config_app = app.conf2['config']['app']
|
||||
self.config_main = app.conf2['config']['tree']
|
||||
self.config_items = list(app.conf2['tree'])
|
||||
self.config_app = app.conf2["config"]["app"]
|
||||
self.config_main = app.conf2["config"]["tree"]
|
||||
self.config_items = list(app.conf2["tree"])
|
||||
# THIS MAKE A BUG !!!! self.plugin_loader = LoadPlugin(AlberoPlugins)
|
||||
|
||||
|
||||
self.plugins = [
|
||||
'init',
|
||||
'loop',
|
||||
'hier',
|
||||
]
|
||||
"init",
|
||||
"loop",
|
||||
"hier",
|
||||
]
|
||||
|
||||
# Auto init
|
||||
self.backends = self.config_items
|
||||
|
||||
|
||||
def query(self, key=None, scope=None, trace=False):
|
||||
backends = self.get_backends(key=key, scope=scope, trace=trace)
|
||||
ret = self.get_results(backends, trace=trace)
|
||||
@ -160,34 +158,31 @@ class BackendsManager(Manager):
|
||||
# Prepare plugins
|
||||
plugin_loader = LoadPlugin(AlberoPlugins)
|
||||
_run = {
|
||||
"key": key,
|
||||
"scope": scope,
|
||||
}
|
||||
"key": key,
|
||||
"scope": scope,
|
||||
}
|
||||
|
||||
# Preprocess backends plugins
|
||||
backends = self.config_items
|
||||
log.debug(f"Backend preprocessing of {len(backends)} elements")
|
||||
for plugin in self.plugins:
|
||||
#backend_cls = plugin_loader.load('backend', plugin)
|
||||
plugin = plugin_loader.load(
|
||||
'backend', plugin
|
||||
)()
|
||||
# backend_cls = plugin_loader.load('backend', plugin)
|
||||
plugin = plugin_loader.load("backend", plugin)()
|
||||
|
||||
log.debug(f"Run {plugin}")
|
||||
new_backend, _run = plugin.process(backends, _run)
|
||||
|
||||
assert(isinstance(new_backend, list)), f"Got: {new_backend}"
|
||||
assert(isinstance(_run, dict)), f"Got: {_run}"
|
||||
assert isinstance(new_backend, list), f"Got: {new_backend}"
|
||||
assert isinstance(_run, dict), f"Got: {_run}"
|
||||
backends = new_backend
|
||||
|
||||
# pprint (backends)
|
||||
for i in backends:
|
||||
assert (i.get('engine')), f"Got: {i}"
|
||||
assert i.get("engine"), f"Got: {i}"
|
||||
|
||||
log.debug(f"Backend preprocessing made {len(backends)} elements")
|
||||
return backends
|
||||
|
||||
|
||||
def get_results(self, backends, trace=False):
|
||||
|
||||
# Prepare plugins
|
||||
@ -195,20 +190,18 @@ class BackendsManager(Manager):
|
||||
|
||||
new_results = []
|
||||
for backend in backends:
|
||||
#result_cls = result_loader.load('result', result)
|
||||
# result_cls = result_loader.load('result', result)
|
||||
# print ("BACKKENNDNNDNDNDND")
|
||||
# pprint(backend)
|
||||
|
||||
engine = plugin_loader.load(
|
||||
'engine', backend['engine']
|
||||
)(
|
||||
backend,
|
||||
parent=self, app=self.app)
|
||||
engine = plugin_loader.load("engine", backend["engine"])(
|
||||
backend, parent=self, app=self.app
|
||||
)
|
||||
|
||||
log.debug(f"Run engine: {engine}")
|
||||
new_result = engine.process()
|
||||
|
||||
assert(isinstance(new_result, list)), f"Got: {new_result}"
|
||||
assert isinstance(new_result, list), f"Got: {new_result}"
|
||||
new_results.extend(new_result)
|
||||
|
||||
# Filter out? Not here !new_results = [i for i in new_results if i['found'] ]
|
||||
@ -217,65 +210,60 @@ class BackendsManager(Manager):
|
||||
return new_results
|
||||
|
||||
|
||||
|
||||
class RulesManager(Manager):
|
||||
|
||||
plugins_kind = ['strategy']
|
||||
plugins_kind = ["strategy"]
|
||||
|
||||
_schema_props_new = {
|
||||
"rule": {
|
||||
"default": ".*",
|
||||
"optional": True,
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
},
|
||||
{
|
||||
"type": "null",
|
||||
},
|
||||
],
|
||||
},
|
||||
"strategy": {
|
||||
"type": "string",
|
||||
"default": "schema",
|
||||
# "default": "last",
|
||||
"optional": True,
|
||||
# "enum": ["first", "last", "merge"],
|
||||
},
|
||||
|
||||
"trace": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
},
|
||||
"explain": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
},
|
||||
}
|
||||
|
||||
_props_position = 'oneOf/1/properties'
|
||||
_schema_props_default = {
|
||||
"$schema": 'http://json-schema.org/draft-07/schema#',
|
||||
"default": "",
|
||||
"$def": {
|
||||
"items": {},
|
||||
},
|
||||
"rule": {
|
||||
"default": ".*",
|
||||
"optional": True,
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "BLAAAAHHH"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": True,
|
||||
"default": {},
|
||||
"properties": { "$ref": "#/$defs/name" },
|
||||
"type": "null",
|
||||
},
|
||||
]
|
||||
}
|
||||
],
|
||||
},
|
||||
"strategy": {
|
||||
"type": "string",
|
||||
"default": "schema",
|
||||
# "default": "last",
|
||||
"optional": True,
|
||||
# "enum": ["first", "last", "merge"],
|
||||
},
|
||||
"trace": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
},
|
||||
"explain": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
},
|
||||
}
|
||||
|
||||
_props_position = "oneOf/1/properties"
|
||||
_schema_props_default = {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"default": "",
|
||||
"$def": {
|
||||
"items": {},
|
||||
},
|
||||
"oneOf": [
|
||||
{"type": "string", "default": "BLAAAAHHH"},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": True,
|
||||
"default": {},
|
||||
"properties": {"$ref": "#/$defs/name"},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
OLD_rule_schema = {
|
||||
"$schema": 'http://json-schema.org/draft-07/schema#',
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
"properties": {
|
||||
@ -286,73 +274,70 @@ class RulesManager(Manager):
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": True,
|
||||
"default": {},
|
||||
"properties": { "$ref": "#/$defs/name" },
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
"properties": {"$ref": "#/$defs/name"},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
|
||||
self.config_app = app.conf2['config']['app']
|
||||
self.config_main = app.conf2['config']['rules']
|
||||
self.config_items = list(app.conf2['rules'])
|
||||
self.config_app = app.conf2["config"]["app"]
|
||||
self.config_main = app.conf2["config"]["rules"]
|
||||
self.config_items = list(app.conf2["rules"])
|
||||
|
||||
def get_result(self, candidates, key=None, scope=None, trace=False, explain=False):
|
||||
#trace=False
|
||||
# trace=False
|
||||
|
||||
rules = self.config_items
|
||||
key = key or ''
|
||||
key = key or ""
|
||||
|
||||
# Filter out invalid candidates
|
||||
matched_candidates = [i for i in candidates if i['found'] == True]
|
||||
matched_candidates = [i for i in candidates if i["found"] == True]
|
||||
if len(matched_candidates) == 0:
|
||||
log.debug("No matched candidates")
|
||||
return None
|
||||
|
||||
|
||||
# Look for matching key in rules defiunitions
|
||||
regex_support = False
|
||||
matched_rule = {}
|
||||
if regex_support:
|
||||
raise Exception("Not Implemented")
|
||||
else:
|
||||
rule = [ i for i in rules if i.get('rule') == key ]
|
||||
if len(rule) == 0:
|
||||
log.debug(f"No matched rule for {key}, applying defaults")
|
||||
else:
|
||||
matched_rule = rule[0]
|
||||
log.debug(f"Matcher rule for {key}: {matched_rule}")
|
||||
|
||||
matched_rule['trace'] = trace
|
||||
matched_rule['explain'] = explain
|
||||
rule = [i for i in rules if i.get("rule") == key]
|
||||
if len(rule) == 0:
|
||||
log.debug(f"No matched rule for %s, applying defaults", key)
|
||||
else:
|
||||
matched_rule = rule[0]
|
||||
log.debug(f"Matcher rule for {key}: {matched_rule}")
|
||||
|
||||
matched_rule["trace"] = trace
|
||||
matched_rule["explain"] = explain
|
||||
schema_validate(matched_rule, self._schema_props_default)
|
||||
|
||||
|
||||
|
||||
# Prepare plugins
|
||||
assert(isinstance(matched_candidates, list)), f"Got: {matched_candidates}"
|
||||
assert(isinstance(matched_rule, dict)), f"Got: {matched_rule}"
|
||||
strategy = matched_rule.get('strategy', 'schema')
|
||||
assert isinstance(matched_candidates, list), f"Got: {matched_candidates}"
|
||||
assert isinstance(matched_rule, dict), f"Got: {matched_rule}"
|
||||
strategy = matched_rule.get("strategy", "schema")
|
||||
log.debug(f"Key '{key}' matched rule '{rule}' with '{strategy}' strategy")
|
||||
|
||||
# Load plugin
|
||||
log.debug(f"Run strategy: {strategy}")
|
||||
plugin_loader = LoadPlugin(AlberoPlugins)
|
||||
strategy = plugin_loader.load('strategy',
|
||||
strategy,
|
||||
)(parent=self, app=self.app)
|
||||
strategy = plugin_loader.load(
|
||||
"strategy",
|
||||
strategy,
|
||||
)(parent=self, app=self.app)
|
||||
new_result = strategy.process(matched_candidates, matched_rule)
|
||||
|
||||
return new_result
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
|
||||
|
||||
import copy
|
||||
|
||||
# from pathlib import Path
|
||||
# from albero.utils import render_template
|
||||
# from albero.plugin.common import PluginBackendClass
|
||||
# from pprint import pprint
|
||||
#
|
||||
#
|
||||
# import logging
|
||||
# import anyconfig
|
||||
# import textwrap
|
||||
@ -13,55 +12,55 @@ import copy
|
||||
from albero.plugin.common import PluginBackendClass
|
||||
from pprint import pprint
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Plugin(PluginBackendClass):
|
||||
|
||||
_plugin_name = "hier"
|
||||
_schema_props_new = {
|
||||
"hier": {
|
||||
"default": None,
|
||||
"optional": True,
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
},
|
||||
{
|
||||
"additionalProperties": True,
|
||||
"properties": {
|
||||
"data": {
|
||||
"default": None,
|
||||
"anyOf": [
|
||||
{ "type": "null" },
|
||||
{ "type": "string" },
|
||||
{ "type": "array" },
|
||||
]
|
||||
},
|
||||
"var": {
|
||||
"type": "string",
|
||||
"default": "hier_item",
|
||||
"optional": True,
|
||||
},
|
||||
"separator": {
|
||||
"type": "string",
|
||||
"default": "/",
|
||||
"optional": True,
|
||||
},
|
||||
"reversed": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
"optional": True,
|
||||
},
|
||||
"hier": {
|
||||
"default": None,
|
||||
"optional": True,
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
},
|
||||
{
|
||||
"additionalProperties": True,
|
||||
"properties": {
|
||||
"data": {
|
||||
"default": None,
|
||||
"anyOf": [
|
||||
{"type": "null"},
|
||||
{"type": "string"},
|
||||
{"type": "array"},
|
||||
],
|
||||
},
|
||||
"var": {
|
||||
"type": "string",
|
||||
"default": "hier_item",
|
||||
"optional": True,
|
||||
},
|
||||
"separator": {
|
||||
"type": "string",
|
||||
"default": "/",
|
||||
"optional": True,
|
||||
},
|
||||
"reversed": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
"optional": True,
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
def process(self, backends: list, ctx: dict) -> (list, dict):
|
||||
|
||||
@ -79,13 +78,13 @@ class Plugin(PluginBackendClass):
|
||||
hier_var = plugin_config.get("var", "item")
|
||||
hier_sep = plugin_config.get("separator", "/")
|
||||
if isinstance(hier_data, str):
|
||||
hier_data = cand['_run']['scope'].get(hier_data, None)
|
||||
hier_data = cand["_run"]["scope"].get(hier_data, None)
|
||||
|
||||
# Build a new list
|
||||
|
||||
if isinstance(hier_data, str):
|
||||
r = hier_data.split(hier_sep)
|
||||
assert (isinstance(r, list)), f"Got: {r}"
|
||||
assert isinstance(r, list), f"Got: {r}"
|
||||
|
||||
ret1 = []
|
||||
for index, part in enumerate(r):
|
||||
@ -93,7 +92,7 @@ class Plugin(PluginBackendClass):
|
||||
try:
|
||||
prefix = ret1[index - 1]
|
||||
except IndexError:
|
||||
prefix = f'{hier_sep}'
|
||||
prefix = f"{hier_sep}"
|
||||
prefix = ""
|
||||
item = f"{prefix}{part}{hier_sep}"
|
||||
ret1.append(item)
|
||||
@ -102,15 +101,13 @@ class Plugin(PluginBackendClass):
|
||||
for item in ret1:
|
||||
_cand = copy.deepcopy(cand)
|
||||
run = {
|
||||
"index": index,
|
||||
"hier_value": item,
|
||||
"hier_var": hier_var,
|
||||
}
|
||||
_cand['_run']['hier'] = run
|
||||
_cand['_run']['scope'][hier_var] = item
|
||||
"index": index,
|
||||
"hier_value": item,
|
||||
"hier_var": hier_var,
|
||||
}
|
||||
_cand["_run"]["hier"] = run
|
||||
_cand["_run"]["scope"][hier_var] = item
|
||||
ret2.append(_cand)
|
||||
|
||||
new_backends.extend(ret2)
|
||||
return new_backends, ctx
|
||||
|
||||
|
||||
|
||||
@ -1,37 +1,35 @@
|
||||
|
||||
|
||||
from albero.plugin.common import PluginBackendClass
|
||||
from pprint import pprint
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
import copy
|
||||
|
||||
|
||||
class Plugin(PluginBackendClass):
|
||||
|
||||
_plugin_name = "init"
|
||||
_schema_props_new = None
|
||||
|
||||
default_engine = 'jerakia'
|
||||
default_engine = "jerakia"
|
||||
|
||||
def process(self, backends: list, ctx: dict) -> (list, dict):
|
||||
|
||||
new_backends = []
|
||||
for index, item in enumerate(backends):
|
||||
default = {
|
||||
"value": item,
|
||||
}
|
||||
"value": item,
|
||||
}
|
||||
|
||||
if not isinstance(item, dict):
|
||||
item = default
|
||||
|
||||
item['engine'] = item.get('engine', self.default_engine )
|
||||
item['_run'] = copy.deepcopy(ctx)
|
||||
item['_run']['backend'] = {
|
||||
"index": index,
|
||||
}
|
||||
item["engine"] = item.get("engine", self.default_engine)
|
||||
item["_run"] = copy.deepcopy(ctx)
|
||||
item["_run"]["backend"] = {
|
||||
"index": index,
|
||||
}
|
||||
new_backends.append(item)
|
||||
|
||||
return new_backends, ctx
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import copy
|
||||
from pathlib import Path
|
||||
from albero.utils import render_template
|
||||
@ -14,56 +12,56 @@ import textwrap
|
||||
class Plugin(PluginBackendClass):
|
||||
|
||||
_plugin_name = "loop"
|
||||
_plugin_help = """
|
||||
_plugin_help = (
|
||||
"""
|
||||
This module helps to loop over a backend
|
||||
""",
|
||||
)
|
||||
_schema_props_new = {
|
||||
"loop": {
|
||||
"description": _plugin_help,
|
||||
"default": None,
|
||||
"optional": True,
|
||||
"examples": [
|
||||
{
|
||||
"value": "site/{{ loop_env }}/config/{{ os }}",
|
||||
"loop": {
|
||||
"var": "loop_env",
|
||||
"data": [
|
||||
"dev",
|
||||
"preprod",
|
||||
"prod",
|
||||
],
|
||||
},
|
||||
"comment": "The module will loop three time over the value, and the variable `loop_env` will consecutely have `dev`, `preprod` and `prod` as value",
|
||||
{
|
||||
"value": "site/{{ loop_env }}/config/{{ os }}",
|
||||
"loop": {
|
||||
"var": "loop_env",
|
||||
"data": [
|
||||
"dev",
|
||||
"preprod",
|
||||
"prod",
|
||||
],
|
||||
},
|
||||
{
|
||||
"value": "site/{{ loop_env2 }}/config/{{ os }}",
|
||||
"loop": {
|
||||
"var": "loop_env2",
|
||||
"data": "my_scope_var",
|
||||
},
|
||||
"comment": "Like the previous example, but it will fetch the list from any scope variables",
|
||||
"comment": "The module will loop three time over the value, and the variable `loop_env` will consecutely have `dev`, `preprod` and `prod` as value",
|
||||
},
|
||||
{
|
||||
"value": "site/{{ loop_env2 }}/config/{{ os }}",
|
||||
"loop": {
|
||||
"var": "loop_env2",
|
||||
"data": "my_scope_var",
|
||||
},
|
||||
{
|
||||
"loop": None,
|
||||
"comment": "Disable this module, no loop will operate",
|
||||
},
|
||||
|
||||
|
||||
# "loop": {
|
||||
# "var": "my_var",
|
||||
# },
|
||||
# },
|
||||
# "loop": {
|
||||
# "var": "my_var",
|
||||
# },
|
||||
# "example": "",
|
||||
# },
|
||||
# "loop": {
|
||||
# "var": "my_var",
|
||||
# },
|
||||
# "example": "",
|
||||
# },
|
||||
],
|
||||
"comment": "Like the previous example, but it will fetch the list from any scope variables",
|
||||
},
|
||||
{
|
||||
"loop": None,
|
||||
"comment": "Disable this module, no loop will operate",
|
||||
},
|
||||
# "loop": {
|
||||
# "var": "my_var",
|
||||
# },
|
||||
# },
|
||||
# "loop": {
|
||||
# "var": "my_var",
|
||||
# },
|
||||
# "example": "",
|
||||
# },
|
||||
# "loop": {
|
||||
# "var": "my_var",
|
||||
# },
|
||||
# "example": "",
|
||||
# },
|
||||
],
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
@ -71,30 +69,29 @@ class Plugin(PluginBackendClass):
|
||||
"default": {},
|
||||
"title": "Complete config",
|
||||
"description": "",
|
||||
|
||||
"properties": {
|
||||
"data": {
|
||||
"default": None,
|
||||
"optional": False,
|
||||
"title": "Module configuration",
|
||||
"description": "Data list used for iterations. It only accept lists as type. It disable the module if set to `null`.",
|
||||
"anyOf":[
|
||||
{
|
||||
"type": "null",
|
||||
"title": "Disable Module",
|
||||
"description": "Disable the module",
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"title": "Scope variable",
|
||||
"description": "Will look the value of the loop list from the scope. TOFIX: What if variablle does not exists?",
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"title": "Hardcoded list",
|
||||
"description": "Simply enter the list of value to be iterated to.",
|
||||
},
|
||||
]
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"title": "Disable Module",
|
||||
"description": "Disable the module",
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"title": "Scope variable",
|
||||
"description": "Will look the value of the loop list from the scope. TOFIX: What if variablle does not exists?",
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"title": "Hardcoded list",
|
||||
"description": "Simply enter the list of value to be iterated to.",
|
||||
},
|
||||
],
|
||||
},
|
||||
"var": {
|
||||
"type": "string",
|
||||
@ -115,14 +112,12 @@ class Plugin(PluginBackendClass):
|
||||
"title": "Disable",
|
||||
"description": "If set to null, it disable the module",
|
||||
},
|
||||
]
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def process(self, backends: list, ctx: dict) -> (list, dict):
|
||||
|
||||
|
||||
new_backends = []
|
||||
for cand in backends:
|
||||
cand = dict(cand)
|
||||
@ -137,26 +132,23 @@ class Plugin(PluginBackendClass):
|
||||
# Retrieve config data
|
||||
loop_var = loop_config.get("var", "item")
|
||||
if isinstance(loop_data, str):
|
||||
loop_data = cand['_run']['scope'].get(loop_data, None)
|
||||
assert (isinstance(loop_data, list)), f"Got: {loop_data}"
|
||||
loop_data = cand["_run"]["scope"].get(loop_data, None)
|
||||
assert isinstance(loop_data, list), f"Got: {loop_data}"
|
||||
|
||||
# Build a new list
|
||||
ret = []
|
||||
for idx, item in enumerate(loop_data):
|
||||
_cand = copy.deepcopy(cand)
|
||||
run = {
|
||||
"loop_index": idx,
|
||||
"loop_value": item,
|
||||
"loop_var": loop_var,
|
||||
}
|
||||
_cand['_run']['loop'] = run
|
||||
_cand['_run']['scope'][loop_var] = item
|
||||
#_cand.scope[loop_var] = item
|
||||
"loop_index": idx,
|
||||
"loop_value": item,
|
||||
"loop_var": loop_var,
|
||||
}
|
||||
_cand["_run"]["loop"] = run
|
||||
_cand["_run"]["scope"][loop_var] = item
|
||||
# _cand.scope[loop_var] = item
|
||||
ret.append(_cand)
|
||||
|
||||
new_backends.extend(ret)
|
||||
|
||||
return new_backends, ctx
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
# from box import Box
|
||||
import textwrap
|
||||
from pprint import pprint
|
||||
@ -9,6 +8,7 @@ import yaml
|
||||
import json
|
||||
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
from albero.utils import schema_validate
|
||||
@ -16,7 +16,7 @@ import copy
|
||||
|
||||
# Candidate Classes
|
||||
# =============================
|
||||
class Candidate():
|
||||
class Candidate:
|
||||
engine = None
|
||||
found = False
|
||||
data = None
|
||||
@ -32,40 +32,36 @@ class Candidate():
|
||||
|
||||
def _report_data(self, data=None):
|
||||
default_data = {
|
||||
#"rule": self.config,
|
||||
"value": self.engine._plugin_value,
|
||||
"data": self.data,
|
||||
}
|
||||
# "rule": self.config,
|
||||
"value": self.engine._plugin_value,
|
||||
"data": self.data,
|
||||
}
|
||||
data = data or default_data
|
||||
d = json.dumps(data, indent=2) #, sort_keys=True, )
|
||||
d = json.dumps(data, indent=2) # , sort_keys=True, )
|
||||
return d
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Generic Classes
|
||||
# =============================
|
||||
class PluginClass():
|
||||
class PluginClass:
|
||||
_plugin_type = "none"
|
||||
_plugin_value = None
|
||||
|
||||
_schema_props_new = "UNSET PLUGIN PROPRIETIES"
|
||||
|
||||
_schema_props_plugin = {
|
||||
"engine": {
|
||||
"type": "string",
|
||||
# TODO: Fix this ug
|
||||
"default": "jerakia"
|
||||
},
|
||||
"value": {},
|
||||
}
|
||||
"engine": {
|
||||
"type": "string",
|
||||
# TODO: Fix this ug
|
||||
"default": "jerakia",
|
||||
},
|
||||
"value": {},
|
||||
}
|
||||
|
||||
def __repr__(self):
|
||||
kind = self._plugin_type
|
||||
name = self._plugin_name
|
||||
value = getattr(self, 'value', 'NO VALUE')
|
||||
value = getattr(self, "value", "NO VALUE")
|
||||
return f"{kind}.{name}:{value}"
|
||||
|
||||
def __init__(self, config=None, parent=None, app=None):
|
||||
@ -79,61 +75,63 @@ class PluginClass():
|
||||
|
||||
def _init(self):
|
||||
pass
|
||||
|
||||
def _validate(self):
|
||||
pass
|
||||
|
||||
|
||||
class PluginBackendClass(PluginClass):
|
||||
_plugin_type = "backend"
|
||||
|
||||
def _init(self):
|
||||
pass
|
||||
|
||||
|
||||
class PluginStrategyClass(PluginClass):
|
||||
_plugin_type = "strategy"
|
||||
|
||||
def _init(self):
|
||||
pass
|
||||
|
||||
|
||||
class PluginEngineClass(PluginClass):
|
||||
_plugin_type = "engine"
|
||||
|
||||
_schema_props_default = {
|
||||
"value": {
|
||||
"default": "UNSET",
|
||||
"value": {
|
||||
"default": "UNSET",
|
||||
},
|
||||
#### SHOULD NOT BE HERE
|
||||
"hier": {
|
||||
"additionalProperties": True,
|
||||
"optional": True,
|
||||
"properties": {
|
||||
"var": {
|
||||
"type": "string",
|
||||
"default": "item",
|
||||
"optional": True,
|
||||
},
|
||||
|
||||
#### SHOULD NOT BE HERE
|
||||
"hier": {
|
||||
"additionalProperties": True,
|
||||
"optional": True,
|
||||
"properties": {
|
||||
"var": {
|
||||
"type": "string",
|
||||
"default": "item",
|
||||
"optional": True,
|
||||
},
|
||||
"data": {
|
||||
"default": None,
|
||||
"anyOf": [
|
||||
{ "type": "null" },
|
||||
{ "type": "string" },
|
||||
{ "type": "array" },
|
||||
]
|
||||
},
|
||||
"separator": {
|
||||
"type": "string",
|
||||
"default": "/",
|
||||
"optional": True,
|
||||
},
|
||||
"reversed": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
"optional": True,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"data": {
|
||||
"default": None,
|
||||
"anyOf": [
|
||||
{"type": "null"},
|
||||
{"type": "string"},
|
||||
{"type": "array"},
|
||||
],
|
||||
},
|
||||
"separator": {
|
||||
"type": "string",
|
||||
"default": "/",
|
||||
"optional": True,
|
||||
},
|
||||
"reversed": {
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
"optional": True,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Default plugin API Methods
|
||||
# =====================
|
||||
@ -143,13 +141,13 @@ class PluginEngineClass(PluginClass):
|
||||
def _validate(self):
|
||||
|
||||
# Build schema
|
||||
schema_keys = [a for a in dir(self) if a.startswith('_schema_props_')]
|
||||
schema_keys = [a for a in dir(self) if a.startswith("_schema_props_")]
|
||||
props = {}
|
||||
for key in schema_keys:
|
||||
schema = getattr(self, key)
|
||||
props.update(schema)
|
||||
self.schema = {
|
||||
"$schema": 'http://json-schema.org/draft-07/schema#',
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"additionalProperties": True,
|
||||
"properties": props,
|
||||
@ -159,72 +157,75 @@ class PluginEngineClass(PluginClass):
|
||||
self.config = schema_validate(self.config, self.schema)
|
||||
return True
|
||||
|
||||
|
||||
# Public Methods
|
||||
# =====================
|
||||
def dump(self):
|
||||
ret = {
|
||||
"config": self.config,
|
||||
}
|
||||
}
|
||||
return ret
|
||||
|
||||
def lookup_candidates(self, key=None, scope=None):
|
||||
raise Exception (f"Module does not implement this method :(")
|
||||
raise Exception(f"Module does not implement this method :(")
|
||||
# It must always return a list of `Candidate` instances
|
||||
return []
|
||||
|
||||
def _example(self):
|
||||
print (f"Module does not implement this method :(")
|
||||
print(f"Module does not implement this method :(")
|
||||
return None
|
||||
|
||||
|
||||
# File plugins Extensions
|
||||
# =============================
|
||||
|
||||
class PluginFileGlob():
|
||||
|
||||
class PluginFileGlob:
|
||||
|
||||
_schema_props_glob = {
|
||||
"glob": {
|
||||
"additionalProperties": False,
|
||||
"default": {
|
||||
"file": "ansible.yaml",
|
||||
},
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"default": "ansible",
|
||||
"optional": True,
|
||||
},
|
||||
"ext": {
|
||||
"type": "array",
|
||||
"default": [ "yml", "yaml" ],
|
||||
"optional": True,
|
||||
},
|
||||
}
|
||||
}
|
||||
"glob": {
|
||||
"additionalProperties": False,
|
||||
"default": {
|
||||
"file": "ansible.yaml",
|
||||
},
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"default": "ansible",
|
||||
"optional": True,
|
||||
},
|
||||
"ext": {
|
||||
"type": "array",
|
||||
"default": ["yml", "yaml"],
|
||||
"optional": True,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
def _glob(self, item):
|
||||
|
||||
# DIRECT CALL TO APP< TOFIX
|
||||
app_config = self.app.conf2
|
||||
root = app_config.get("default", {}).get("config", {}).get("root", f"{Path.cwd()}/tree")
|
||||
#root = self.app.conf2.config.app.root
|
||||
root = (
|
||||
app_config.get("default", {})
|
||||
.get("config", {})
|
||||
.get("root", f"{Path.cwd()}/tree")
|
||||
)
|
||||
# root = self.app.conf2.config.app.root
|
||||
# TOFIX print ("ITEM! %s" % type(root))
|
||||
# TOFIX print ("ITEM2 %s" % self.app.conf2.config.app.root)
|
||||
|
||||
glob_config = self.config.get("glob", {})
|
||||
glob_file = glob_config['file']
|
||||
#glob_ext = glob_config['ext']
|
||||
glob_file = glob_config["file"]
|
||||
# glob_ext = glob_config['ext']
|
||||
|
||||
item = Path(root) / Path(item) / Path(glob_file)
|
||||
item = f"{item}"
|
||||
#file = f"{glob_file}.{glob_ext}"
|
||||
# file = f"{glob_file}.{glob_ext}"
|
||||
|
||||
#print ("ITEM %s" % item)
|
||||
# print ("ITEM %s" % item)
|
||||
files = glob.glob(item)
|
||||
|
||||
log.debug (f"Matched file for glob '{item}': {files}")
|
||||
log.debug(f"Matched file for glob '{item}': {files}")
|
||||
|
||||
return files
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
from pathlib import Path
|
||||
from albero.utils import render_template
|
||||
from albero.plugin.common import PluginEngineClass, PluginFileGlob, Candidate
|
||||
@ -10,55 +9,55 @@ import textwrap
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FileCandidate(Candidate):
|
||||
path = None
|
||||
|
||||
def _report_data(self):
|
||||
data = {
|
||||
#"rule": self.config,
|
||||
"value": self.engine._plugin_value,
|
||||
"data": self.data,
|
||||
"path": str(self.path.relative_to(Path.cwd())),
|
||||
}
|
||||
# "rule": self.config,
|
||||
"value": self.engine._plugin_value,
|
||||
"data": self.data,
|
||||
"path": str(self.path.relative_to(Path.cwd())),
|
||||
}
|
||||
data = dict(self.config)
|
||||
return super()._report_data(data)
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginEngineClass, PluginFileGlob):
|
||||
|
||||
_plugin_name = 'jerakia'
|
||||
_plugin_name = "jerakia"
|
||||
|
||||
### OLD
|
||||
_plugin_engine = "jerakia"
|
||||
# _schema_props_files = {
|
||||
_schema_props_new = {
|
||||
"path": {
|
||||
"anyOf": [
|
||||
{
|
||||
"path": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
def _init(self):
|
||||
|
||||
paths = self.config.get('path', self.config.get('value'))
|
||||
paths = self.config.get("path", self.config.get("value"))
|
||||
if isinstance(paths, str):
|
||||
paths = [paths]
|
||||
elif isinstance(paths, list):
|
||||
pass
|
||||
else:
|
||||
raise Exception (f"Unsupported path value, expected str or dict, got: {paths} in {self.config}")
|
||||
raise Exception(
|
||||
f"Unsupported path value, expected str or dict, got: {paths} in {self.config}"
|
||||
)
|
||||
|
||||
self.paths = paths
|
||||
self.value = paths
|
||||
@ -78,7 +77,6 @@ class Plugin(PluginEngineClass, PluginFileGlob):
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _show_paths(self, scope):
|
||||
|
||||
parsed = self._preprocess(scope)
|
||||
@ -93,14 +91,12 @@ class Plugin(PluginEngineClass, PluginFileGlob):
|
||||
|
||||
return ret3
|
||||
|
||||
|
||||
def process(self):
|
||||
|
||||
|
||||
#scope = self.scope
|
||||
# scope = self.scope
|
||||
# pprint (self.config)
|
||||
scope = dict(self.config['_run']['scope'])
|
||||
key = self.config['_run']['key']
|
||||
scope = dict(self.config["_run"]["scope"])
|
||||
key = self.config["_run"]["key"]
|
||||
assert isinstance(scope, dict), f"Got: {scope}"
|
||||
assert isinstance(key, (str, type(None))), f"Got: {key}"
|
||||
|
||||
@ -125,13 +121,13 @@ class Plugin(PluginEngineClass, PluginFileGlob):
|
||||
|
||||
# Build result object
|
||||
result = {}
|
||||
result['run'] = {
|
||||
'path': path,
|
||||
'rel_path': str(Path(path).relative_to(Path.cwd())),
|
||||
}
|
||||
result['parent'] = self.config
|
||||
result['data'] = data
|
||||
result['found'] = found
|
||||
result["run"] = {
|
||||
"path": path,
|
||||
"rel_path": str(Path(path).relative_to(Path.cwd())),
|
||||
}
|
||||
result["parent"] = self.config
|
||||
result["data"] = data
|
||||
result["found"] = found
|
||||
|
||||
ret.append(result)
|
||||
|
||||
@ -141,7 +137,7 @@ class Plugin(PluginEngineClass, PluginFileGlob):
|
||||
|
||||
# # Read raw file content
|
||||
# data = anyconfig.load(path, ac_parser="yaml")
|
||||
#
|
||||
#
|
||||
# ret_obj2 ={
|
||||
# "_run": _run,
|
||||
|
||||
@ -183,7 +179,3 @@ class Plugin(PluginEngineClass, PluginFileGlob):
|
||||
# #log.debug(f"Found value: {ret_obj}")
|
||||
# ret_obj.found = found
|
||||
# ret.append(ret_obj)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
|
||||
import logging
|
||||
from albero.plugin.common import PluginStrategyClass
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Plugin(PluginStrategyClass):
|
||||
|
||||
_plugin_name = "last"
|
||||
@ -12,4 +12,3 @@ class Plugin(PluginStrategyClass):
|
||||
def process(self, candidates: list, rule=None) -> (list, dict):
|
||||
|
||||
return candidates[-1]
|
||||
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
import logging
|
||||
from albero.plugin.common import PluginStrategyClass
|
||||
from albero.utils import schema_validate, str_ellipsis
|
||||
@ -11,6 +9,7 @@ from pprint import pprint
|
||||
from jsonmerge import Merger
|
||||
from prettytable import PrettyTable
|
||||
|
||||
|
||||
class Plugin(PluginStrategyClass):
|
||||
|
||||
_plugin_name = "schema"
|
||||
@ -36,11 +35,11 @@ class Plugin(PluginStrategyClass):
|
||||
"data": {
|
||||
"default": None,
|
||||
"optional": False,
|
||||
"anyOf":[
|
||||
{"type": "null"},
|
||||
{"type": "string"},
|
||||
{"type": "array"},
|
||||
]
|
||||
"anyOf": [
|
||||
{"type": "null"},
|
||||
{"type": "string"},
|
||||
{"type": "array"},
|
||||
],
|
||||
},
|
||||
"var": {
|
||||
"type": "string",
|
||||
@ -49,17 +48,17 @@ class Plugin(PluginStrategyClass):
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
default_merge_schema = {
|
||||
"$schema": 'http://json-schema.org/draft-07/schema#',
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"mergeStrategy": "append",
|
||||
# "mergeStrategy": "arrayMergeById",
|
||||
# "mergeStrategy": "arrayMergeById",
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
@ -88,76 +87,123 @@ class Plugin(PluginStrategyClass):
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def process(self, candidates: list, rule=None) -> (list, dict):
|
||||
|
||||
trace = rule['trace']
|
||||
explain = rule['explain']
|
||||
schema = rule.get('schema', None) or self.default_merge_schema
|
||||
trace = rule["trace"]
|
||||
explain = rule["explain"]
|
||||
schema = rule.get("schema", None) or self.default_merge_schema
|
||||
merger = Merger(schema)
|
||||
t = PrettyTable()
|
||||
t1 = PrettyTable()
|
||||
|
||||
new_candidate = None
|
||||
for index, item in enumerate(candidates):
|
||||
new_value = item['data']
|
||||
new_value = item["data"]
|
||||
result = merger.merge(new_candidate, new_value)
|
||||
|
||||
backend_info = dict(item['parent'])
|
||||
backend_info = dict(item["parent"])
|
||||
backend_run = backend_info.pop("_run")
|
||||
if explain:
|
||||
t1.add_row([
|
||||
index,
|
||||
'\nBackendRun: ' + str_ellipsis(json.dumps(
|
||||
backend_run,
|
||||
default=lambda o: '<not serializable>', indent=2), 70),
|
||||
'\nRuleRun: ' + str_ellipsis(json.dumps(
|
||||
item['run'],
|
||||
default=lambda o: '<not serializable>', indent=2), 70),
|
||||
'---\nResult: ' + str_ellipsis(json.dumps(
|
||||
result,
|
||||
default=lambda o: '<not serializable>', indent=2), 70),
|
||||
])
|
||||
t1.add_row(
|
||||
[
|
||||
index,
|
||||
"\nBackendRun: "
|
||||
+ str_ellipsis(
|
||||
json.dumps(
|
||||
backend_run,
|
||||
default=lambda o: "<not serializable>",
|
||||
indent=2,
|
||||
),
|
||||
70,
|
||||
),
|
||||
"\nRuleRun: "
|
||||
+ str_ellipsis(
|
||||
json.dumps(
|
||||
item["run"],
|
||||
default=lambda o: "<not serializable>",
|
||||
indent=2,
|
||||
),
|
||||
70,
|
||||
),
|
||||
"---\nResult: "
|
||||
+ str_ellipsis(
|
||||
json.dumps(
|
||||
result, default=lambda o: "<not serializable>", indent=2
|
||||
),
|
||||
70,
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
if trace:
|
||||
t.add_row([
|
||||
index,
|
||||
'---\nBackendConfig: ' + str_ellipsis(json.dumps(
|
||||
backend_info,
|
||||
default=lambda o: '<not serializable>', indent=2), 70) +
|
||||
'\nBackendRun: ' + str_ellipsis(json.dumps(
|
||||
backend_run,
|
||||
default=lambda o: '<not serializable>', indent=2), 70),
|
||||
|
||||
'---\nRuleConfig: ' + str_ellipsis(json.dumps(
|
||||
rule,
|
||||
default=lambda o: '<not serializable>', indent=2), 70) +
|
||||
'\nRuleRun: ' + str_ellipsis(json.dumps(
|
||||
item['run'],
|
||||
default=lambda o: '<not serializable>', indent=2), 70) +
|
||||
#'\nSource: ' + str_ellipsis(json.dumps(
|
||||
# new_candidate,
|
||||
# default=lambda o: '<not serializable>', indent=2), 70) +
|
||||
'\nNew data: ' + str_ellipsis(json.dumps(
|
||||
new_value,
|
||||
default=lambda o: '<not serializable>', indent=2), 70),
|
||||
|
||||
'---\nResult: ' + str_ellipsis(json.dumps(
|
||||
result,
|
||||
default=lambda o: '<not serializable>', indent=2), 70),
|
||||
]
|
||||
t.add_row(
|
||||
[
|
||||
index,
|
||||
"---\nBackendConfig: "
|
||||
+ str_ellipsis(
|
||||
json.dumps(
|
||||
backend_info,
|
||||
default=lambda o: "<not serializable>",
|
||||
indent=2,
|
||||
),
|
||||
70,
|
||||
)
|
||||
+ "\nBackendRun: "
|
||||
+ str_ellipsis(
|
||||
json.dumps(
|
||||
backend_run,
|
||||
default=lambda o: "<not serializable>",
|
||||
indent=2,
|
||||
),
|
||||
70,
|
||||
),
|
||||
"---\nRuleConfig: "
|
||||
+ str_ellipsis(
|
||||
json.dumps(
|
||||
rule, default=lambda o: "<not serializable>", indent=2
|
||||
),
|
||||
70,
|
||||
)
|
||||
+ "\nRuleRun: "
|
||||
+ str_ellipsis(
|
||||
json.dumps(
|
||||
item["run"],
|
||||
default=lambda o: "<not serializable>",
|
||||
indent=2,
|
||||
),
|
||||
70,
|
||||
)
|
||||
+
|
||||
#'\nSource: ' + str_ellipsis(json.dumps(
|
||||
# new_candidate,
|
||||
# default=lambda o: '<not serializable>', indent=2), 70) +
|
||||
"\nNew data: "
|
||||
+ str_ellipsis(
|
||||
json.dumps(
|
||||
new_value,
|
||||
default=lambda o: "<not serializable>",
|
||||
indent=2,
|
||||
),
|
||||
70,
|
||||
),
|
||||
"---\nResult: "
|
||||
+ str_ellipsis(
|
||||
json.dumps(
|
||||
result, default=lambda o: "<not serializable>", indent=2
|
||||
),
|
||||
70,
|
||||
),
|
||||
]
|
||||
)
|
||||
new_candidate = result
|
||||
|
||||
if trace:
|
||||
t.field_names = ["Index", "Backend", "Rule", "Data"]
|
||||
t.align = 'l'
|
||||
print (t)
|
||||
t.align = "l"
|
||||
print(t)
|
||||
if explain:
|
||||
t1.field_names = ["Index", "Backend", "Rule", "Data"]
|
||||
t1.align = 'l'
|
||||
print('Explain:\n' + repr(t1))
|
||||
t1.align = "l"
|
||||
print("Explain:\n" + repr(t1))
|
||||
|
||||
return new_candidate
|
||||
|
||||
|
||||
|
||||
@ -12,19 +12,20 @@ from pprint import pprint
|
||||
from albero.managers import BackendsManager, RulesManager
|
||||
from albero.utils import schema_validate
|
||||
import anyconfig
|
||||
|
||||
# from box import Box
|
||||
from pathlib import Path
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Query
|
||||
##########################################
|
||||
|
||||
class Query():
|
||||
|
||||
class Query:
|
||||
def __init__(self, app):
|
||||
|
||||
self.app = app
|
||||
@ -43,9 +44,7 @@ class Query():
|
||||
|
||||
ret = {}
|
||||
for i in dir(self):
|
||||
if not i.startswith('_'):
|
||||
if not i.startswith("_"):
|
||||
ret[i] = getattr(self, i)
|
||||
|
||||
pprint (ret)
|
||||
|
||||
|
||||
pprint(ret)
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
from pathlib import Path
|
||||
from jinja2 import Template
|
||||
import yaml
|
||||
@ -10,6 +9,7 @@ import collections
|
||||
|
||||
|
||||
import logging
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -62,19 +62,21 @@ log = logging.getLogger(__name__)
|
||||
# Utils Methods
|
||||
# =====================
|
||||
|
||||
|
||||
def render_template(path, params):
|
||||
"""Render template for a given string"""
|
||||
assert (isinstance(params, dict)), f"Got: {params}"
|
||||
assert isinstance(params, dict), f"Got: {params}"
|
||||
t = Template(path)
|
||||
return t.render(**params)
|
||||
|
||||
#def read_file(file):
|
||||
|
||||
# def read_file(file):
|
||||
# with open(file, 'r') as f:
|
||||
# data = f.read().replace('\n', '')
|
||||
# return data
|
||||
#
|
||||
#
|
||||
#def parse_file(file, fmt='auto'):
|
||||
# def parse_file(file, fmt='auto'):
|
||||
# print ("DEPRECATED")
|
||||
# raise Exception ("parse_file is deprecated")
|
||||
#
|
||||
@ -99,6 +101,7 @@ def render_template(path, params):
|
||||
# Schema Methods
|
||||
# =====================
|
||||
|
||||
|
||||
def _extend_with_default(validator_class):
|
||||
validate_properties = validator_class.VALIDATORS["properties"]
|
||||
|
||||
@ -110,38 +113,43 @@ def _extend_with_default(validator_class):
|
||||
|
||||
try:
|
||||
for error in validate_properties(
|
||||
validator, properties, instance, schema,
|
||||
validator,
|
||||
properties,
|
||||
instance,
|
||||
schema,
|
||||
):
|
||||
continue
|
||||
except Exception as e:
|
||||
print ("CATCHED2222 ", e)
|
||||
print("CATCHED2222 ", e)
|
||||
|
||||
return validators.extend(
|
||||
validator_class, {"properties" : set_defaults},
|
||||
validator_class,
|
||||
{"properties": set_defaults},
|
||||
)
|
||||
|
||||
|
||||
def schema_validate(config, schema):
|
||||
|
||||
# Validate the schema
|
||||
DefaultValidatingDraft7Validator = _extend_with_default(Draft7Validator)
|
||||
try:
|
||||
DefaultValidatingDraft7Validator(schema).validate(config)
|
||||
except Exception as e:
|
||||
print (e)
|
||||
p = list(collections.deque(e.schema_path))
|
||||
p = '/'.join([ str(i) for i in p ])
|
||||
p = f"schema/{p}"
|
||||
raise Exception(
|
||||
f"Failed validating {p} for resource with content: {config} with !!!!!! schema: {schema}"
|
||||
)
|
||||
return config
|
||||
# Validate the schema
|
||||
DefaultValidatingDraft7Validator = _extend_with_default(Draft7Validator)
|
||||
try:
|
||||
DefaultValidatingDraft7Validator(schema).validate(config)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
p = list(collections.deque(e.schema_path))
|
||||
p = "/".join([str(i) for i in p])
|
||||
p = f"schema/{p}"
|
||||
raise Exception(
|
||||
f"Failed validating {p} for resource with content: {config} with !!!!!! schema: {schema}"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
def str_ellipsis(txt, length=120):
|
||||
txt = str(txt)
|
||||
ret = []
|
||||
for string in txt.splitlines():
|
||||
string = (string[:length - 4 ] + ' ...') if len(string) > length else string
|
||||
string = (string[: length - 4] + " ...") if len(string) > length else string
|
||||
ret.append(string)
|
||||
ret = '\n'.join(ret)
|
||||
ret = "\n".join(ret)
|
||||
return ret
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user