Skip to content

Commit 5ae40a7

Browse files
committed
add there important improvement of file nadling
1 parent 02ce718 commit 5ae40a7

File tree

9 files changed

+137
-27
lines changed

9 files changed

+137
-27
lines changed

fmf/base.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import fmf.utils as utils
2020

2121
from io import open
22-
from fmf.utils import log, dict_to_yaml
22+
from fmf.utils import log, dict_to_yaml, FileSorting
2323
from fmf.constants import SUFFIX, IGNORED_DIRECTORIES, MAIN
2424
from fmf.plugin_loader import get_suffixes, get_plugin_for_file
2525
from pprint import pformat as pretty
@@ -452,15 +452,11 @@ def grow(self, path):
452452
except StopIteration:
453453
log.debug("Skipping '{0}' (not accessible).".format(path))
454454
return
455-
# Investigate main.fmf as the first file (for correct inheritance)
456-
filenames = sorted(
457-
[filename for filename in filenames if any(filter(filename.endswith, get_suffixes()))])
458-
try:
459-
filenames.insert(0, filenames.pop(filenames.index(MAIN)))
460-
except ValueError:
461-
pass
455+
456+
filenames_sorted = sorted(
457+
[FileSorting(filename) for filename in filenames if any(filter(filename.endswith, get_suffixes()))])
462458
# Check every metadata file and load data (ignore hidden)
463-
for filename in filenames:
459+
for filename in [filename.value for filename in filenames_sorted]:
464460
if filename.startswith("."):
465461
continue
466462
fullpath = os.path.abspath(os.path.join(dirpath, filename))
@@ -474,16 +470,13 @@ def grow(self, path):
474470
raise (utils.FileError("Failed to parse '{0}'.\n{1}".format(
475471
fullpath, error)))
476472
else:
473+
data = None
477474
plugin = get_plugin_for_file(fullpath)
478475
log.debug("Used plugin {}".format(plugin))
479-
if plugin.file_patters and any(filter(lambda x: re.search(x, fullpath), plugin.file_patters)):
480-
log.info("Matched patters {}".format(plugin.file_patters))
481-
data = plugin().get_data(fullpath)
482-
# ignore results of output if there is None
483-
if data is None:
484-
continue
485-
else:
486-
log.debug("Does not match patters {}".format(plugin.file_patters))
476+
if plugin:
477+
data = plugin().read(fullpath)
478+
# ignore results of output if there is None
479+
if data is None:
487480
continue
488481
log.data(pretty(data))
489482
# Handle main.fmf as data for self
@@ -734,7 +727,7 @@ def __exit__(self, exc_type, exc_val, exc_tb):
734727
with open(source, "w", encoding='utf-8') as file:
735728
file.write(dict_to_yaml(full_data))
736729
else:
737-
plugin().put_data(source, hierarchy, node_data, append, modified, deleted)
730+
plugin().write(source, hierarchy, node_data, append, modified, deleted)
738731

739732
def __getitem__(self, key):
740733
"""

fmf/plugin_loader.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
from functools import lru_cache
22
import inspect
3+
import copy
4+
import yaml
5+
36
from fmf.constants import PLUGIN_ENV, SUFFIX
47
from fmf.utils import log
58
import importlib
69
import os
10+
import re
711

812

913
class Plugin:
@@ -14,19 +18,40 @@ class Plugin:
1418
extensions = list()
1519
file_patters = list()
1620

17-
def get_data(self, filename):
21+
def read(self, filename):
1822
"""
1923
return python dictionary representation of metadata inside file (FMF structure)
2024
"""
2125
raise NotImplementedError("Define own impementation")
2226

23-
def put_data(
27+
@staticmethod
28+
def __define_undefined(hierarchy, modified, append):
29+
output = dict()
30+
current = output
31+
for key in hierarchy:
32+
if key not in current or current[key] is None:
33+
current[key] = dict()
34+
current = current[key]
35+
for k,v in modified.items():
36+
current[k] = v
37+
for k,v in append.items():
38+
current[k] = v
39+
return output
40+
41+
def write(
2442
self, filename, hierarchy, data, append_dict, modified_dict,
2543
deleted_items):
2644
"""
27-
Write data in dictionary representation back to file
45+
Write data in dictionary representation back to file, if not defined, create new fmf file with same name.
46+
When created, nodes will not use plugin method anyway
2847
"""
29-
raise NotImplementedError("Define own impementation")
48+
path = os.path.dirname(filename)
49+
basename = os.path.basename(filename)
50+
current_extension = list(filter(lambda x: basename.endswith(x), self.extensions))[0]
51+
without_extension = basename[0:-len(list(current_extension))]
52+
fmf_file = os.path.join(path, without_extension + ".fmf")
53+
with open(fmf_file, "w") as fd:
54+
yaml.safe_dump(self.__define_undefined(hierarchy, modified_dict, append_dict), stream=fd)
3055

3156

3257
@lru_cache(maxsize=1)
@@ -61,6 +86,6 @@ def get_suffixes():
6186
def get_plugin_for_file(filename):
6287
extension = "." + filename.rsplit(".", 1)[1]
6388
for item in enabled_plugins():
64-
if extension in item.extensions:
89+
if extension in item.extensions and any(filter(lambda x: re.search(x, filename), item.file_patters)):
6590
log.debug("File {} parsed by by plugin {}".format(filename, item))
6691
return item

fmf/plugins/bash.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ def update_data(filename, pattern="^#.*:FMF:"):
2121
out[identifier] = value
2222
return out
2323

24-
def get_data(self, file_name):
24+
def read(self, file_name):
2525
log.info("Processing Item: {}".format(file_name))
2626
return self.update_data(file_name)

fmf/plugins/pytest/plugin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ def update_data(store_dict, func, config):
234234
define_undefined(store_dict, keys, config, filename, cls, test)
235235
return store_dict
236236

237-
def get_data(self, file_name):
237+
def read(self, file_name):
238238
def call_collect(queue, file_name):
239239
"""
240240
have to call in separate process, to avoid problems with pytest multiple collectitons
@@ -268,7 +268,7 @@ def import_test_module(filename):
268268
loader.exec_module(module)
269269
return module
270270

271-
def put_data(
271+
def write(
272272
self, filename, hierarchy, data, append_dict, modified_dict,
273273
deleted_items):
274274
module = self.import_test_module(filename)

fmf/utils.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from io import StringIO
2626

2727
import fmf.base
28+
from fmf.constants import MAIN
2829

2930
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3031
# Constants
@@ -856,3 +857,39 @@ def representer(self, data): return self.represent_mapping(
856857
return output.getvalue().decode('utf-8')
857858
except AttributeError:
858859
return output.getvalue()
860+
861+
862+
class FileSorting:
863+
def __init__(self, value):
864+
self._value = value
865+
866+
@property
867+
def value(self):
868+
return self._value
869+
870+
@property
871+
def splitted(self):
872+
splitted = self._value.rsplit(".", 1)
873+
basename = splitted[0]
874+
suffix = splitted[1] if len(splitted) > 1 else ''
875+
return basename, suffix
876+
877+
@property
878+
def basename(self):
879+
return self.splitted[0]
880+
881+
@property
882+
def suffix(self):
883+
return self.splitted[1]
884+
885+
def __lt__(self, other):
886+
# Investigate main.fmf as the first file (for correct inheritance)
887+
if self.value == MAIN:
888+
return True
889+
# if there are same filenames and other endswith fmf, it has to be last one
890+
elif self.basename == other.basename and other.suffix == "fmf":
891+
return True
892+
elif self.basename == other.basename and self.suffix == "fmf":
893+
return False
894+
else:
895+
return self.value < other.value

tests/tests_plugin/test_basic.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def test_fail():
1414
assert False
1515

1616

17+
@TMT.summary("Some summary")
1718
@pytest.mark.skip
1819
def test_skip():
1920
assert True
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/test_pass:
2+
added_fmf_file: added
3+
summary: Rewrite
4+
tag+: [tier2]

tests/tests_plugin/test_rewrite.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from fmf.plugins.pytest import TMT
2+
3+
4+
@TMT.tag("Tier1")
5+
@TMT.summary("Rewritten")
6+
def test_pass():
7+
assert True

tests/unit/test_plugin.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,13 @@ def setUp(self):
3535
os.environ[PLUGIN_ENV] = "fmf.plugins.pytest"
3636
self.plugin_tree = Tree(self.tempdir)
3737

38+
def tearDown(self):
39+
enabled_plugins.cache_clear()
40+
#rmtree(self.tempdir)
41+
3842
def test_basic(self):
3943
item = self.plugin_tree.find("/test_basic/test_skip")
44+
4045
self.assertFalse(item.data.get("enabled"))
4146
self.assertIn("Jan", item.data["author"])
4247
self.assertIn(
@@ -63,6 +68,28 @@ def test_modify(self):
6368
self.assertIn("tier2", item.data["tag"])
6469
self.assertNotIn("tier", item.data)
6570

71+
def test_rewrite(self):
72+
item = self.plugin_tree.find("/test_rewrite/test_pass")
73+
self.assertNotIn("duration", item.data)
74+
self.assertIn("Tier1", item.data["tag"])
75+
self.assertIn("tier2", item.data["tag"])
76+
self.assertEqual("added", item.data["added_fmf_file"])
77+
self.assertEqual("Rewrite", item.data["summary"])
78+
79+
def test_rewrite_modify(self):
80+
self.test_rewrite()
81+
item = self.plugin_tree.find("/test_rewrite/test_pass")
82+
with item as data:
83+
data["tag+"] += ["tier3"]
84+
data["extra_id"] = 1234
85+
86+
self.plugin_tree = Tree(self.tempdir)
87+
item = self.plugin_tree.find("/test_rewrite/test_pass")
88+
self.test_rewrite()
89+
self.assertEqual(1234, item.data["extra_id"])
90+
self.assertIn("tier3", item.data["tag"])
91+
92+
6693

6794
class Bash(Base):
6895
""" Verify reading data done via plugins """
@@ -73,8 +100,24 @@ def setUp(self):
73100
os.path.join(PLUGIN_PATH, "bash.py"))
74101
self.plugin_tree = Tree(self.tempdir)
75102

76-
def test_pytest_plugin(self):
103+
def test_read(self):
77104
item = self.plugin_tree.find("/runtest")
78105
self.assertIn("tier1", item.data["tag"])
79106
self.assertIn("./runtest.sh", item.data["test"])
80107
self.assertIn("Jan", item.data["author"])
108+
109+
def test_modify(self):
110+
self.assertNotIn("runtest.fmf", os.listdir(self.tempdir))
111+
item = self.plugin_tree.find("/runtest")
112+
self.assertIn("tier1", item.data["tag"])
113+
self.assertIn("./runtest.sh", item.data["test"])
114+
with item as data:
115+
data["tier"] = 0
116+
data["duration"] = "10m"
117+
self.plugin_tree = Tree(self.tempdir)
118+
item = self.plugin_tree.find("/runtest")
119+
self.assertIn("runtest.fmf", os.listdir(self.tempdir))
120+
self.assertEqual("10m", item.data["duration"])
121+
self.assertEqual(0, item.data["tier"])
122+
self.assertIn("tier1", item.data["tag"])
123+
self.assertIn("./runtest.sh", item.data["test"])

0 commit comments

Comments
 (0)