Skip to content

Commit

Permalink
Merge be1049a into 419f2f1
Browse files Browse the repository at this point in the history
  • Loading branch information
jscotka committed Apr 25, 2019
2 parents 419f2f1 + be1049a commit c7a0e92
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 1 deletion.
1 change: 1 addition & 0 deletions _config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
theme: jekyll-theme-merlot
1 change: 1 addition & 0 deletions examples/plugin_resolver/.fmf/version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
2 changes: 2 additions & 0 deletions examples/plugin_resolver/a/b/c/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
x: 4
fourth: True
3 changes: 3 additions & 0 deletions examples/plugin_resolver/a/b/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/c:
x: 3
third: True
3 changes: 3 additions & 0 deletions examples/plugin_resolver/a/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/b/c:
x: 2
second: True
11 changes: 11 additions & 0 deletions examples/plugin_resolver/main.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/a/b/c:
x: 1
first: True

/d/dddd:
y: 1
filtered: asd
tags+: ["a", "b"]
/inherited@dddd:
hallo: world
tags+: ["c"]
25 changes: 24 additions & 1 deletion fmf/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import sys
import shlex
import argparse
import importlib

import fmf
import fmf.utils as utils
Expand All @@ -35,6 +36,7 @@

class Parser(object):
""" Command line options parser """
TreeClass = fmf.Tree

def __init__(self, arguments=None, path=None):
""" Prepare the parser. """
Expand Down Expand Up @@ -110,6 +112,9 @@ def options_utils(self):
group.add_argument(
"--debug", action="store_true",
help="Turn on debugging output, do not catch exceptions")
group.add_argument(
"--plugin", action="store",default="",
help="Enable selected plugin")

def command_ls(self):
""" List names """
Expand Down Expand Up @@ -150,10 +155,25 @@ def command_init(self):
def show(self, brief=False):
""" Show metadata for each path given """
output = []
if self.options.plugin:
if "." not in self.options.plugin:
plugin_name = "fmf.plugins." + self.options.plugin
else:
plugin_name = self.options.plugin
utils.info("Using plugin: {}".format(plugin_name))
try:
module = importlib.import_module(plugin_name)
except (NameError, ImportError):
raise utils.GeneralError("Unable to find python module plugin: {}".format(plugin_name))
self.TreeClass = module.Tree
for path in self.options.paths or ["."]:
if self.options.verbose:
utils.info("Checking {0} for metadata.".format(path))
tree = fmf.Tree(path)
tree = self.TreeClass(path)
for item in dir(tree):
# call all plugin functions if any for tree
if item.startswith("plugin"):
getattr(tree, item)()
for node in tree.prune(
self.options.whole, self.options.keys, self.options.names,
self.options.filters):
Expand Down Expand Up @@ -193,3 +213,6 @@ def main(arguments=None, path=None):
""" Parse options, do what is requested """
parser = Parser(arguments, path)
return parser.output

if __name__ == "__main__":
main()
Empty file added fmf/plugins/__init__.py
Empty file.
82 changes: 82 additions & 0 deletions fmf/plugins/reference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import logging
import re

"""
Module handling FMF stored metadata for classes and resolve references by special tag prefix "@"
"""

from fmf import Tree as TreeOrigin

logger = logging.getLogger(__name__)


class Tree(TreeOrigin):
"""
FMF Extension. Allows to use references via @ to another items -> usefull for rulesets
"""

def __remove_append_items(self, whole=False):
"""
internal method, delete all append items (ends with +)
:param whole: pass thru 'whole' param to climb
:return: None
"""
for node in self.climb(whole=whole):
for key in sorted(node.data.keys()):
if key.endswith('+'):
del node.data[key]

def plugin1(self, datatrees=None, whole=False):
"""
Reference name resolver (eg. /a/b/c/d@.x.y or /a/b/c/@y will search data in .x.y or y nodes)
there are used regular expressions (re.search) to match names
it uses simple references schema, do not use references to another references,
avoid usind / in reference because actual solution creates also these tree items.
datatree contains for example data like (original check data)
/dockerfile/maintainer_check:
class: SomeClass
tags: [dockerfile]
and reference could be like (ruleset)
/default/check1@maintainer_check:
tags+: [required]
will produce output (output ruleset tree):
/default/check1@maintainer_check:
class: SomeClass
tags: [dockerfile, required]
:param whole: 'whole' param of original climb method, in colin this is not used anyhow now
iterate over all items not only leaves if True
:param datatrees: list of original trees with testcases to contain parent nodes
:return: None
"""
if datatrees is None:
datatrees = [self]
if not isinstance(datatrees, list):
raise ValueError("datatrees argument has to be list of fmf trees")
reference_nodes = self.prune(whole=whole, names=["@"])
for node in reference_nodes:
node.data = node.original_data
ref_item_name = node.name.rsplit("@", 1)[1]
# match item what does not contain @ before name, otherwise it
# match same item
reference_node = None
for datatree in datatrees:
reference_node = datatree.search("[^@]%s" % ref_item_name)
if reference_node is not None:
break
if not reference_node:
raise ValueError("Unable to find reference for node: %s via name search: %s" %
(node.name, ref_item_name))
logger.debug("MERGING: %s @ %s from %s",
node.name,
reference_node.name,
reference_node.root)
node.merge(parent=reference_node)

self.__remove_append_items(whole=whole)

def search(self, name):
""" Search node with given name based on regexp, basic method (find) uses equality"""
for node in self.climb():
if re.search(name, node.name):
return node
return None

0 comments on commit c7a0e92

Please sign in to comment.