Skip to content

Commit 38d08e0

Browse files
authored
Merge pull request #42 from lrivallain/emptyConfig
Fix #38
2 parents a8e946e + 32651c3 commit 38d08e0

File tree

5 files changed

+106
-28
lines changed

5 files changed

+106
-28
lines changed

README.rst

+16-11
Original file line numberDiff line numberDiff line change
@@ -79,20 +79,25 @@ You can get the usage help by using the ``-h``/``--help`` flag:
7979

8080
Usage: vro-diff [OPTIONS] COMPARED_PACKAGE
8181

82-
Compare two vRealize Orchestrator packages.
82+
Compare two vRealize Orchestrator packages.
8383

84-
Use the [--reference_package] option to specify the reference package.
84+
Use the [-r/--reference_package] option to specify the reference package.
8585

8686
Options:
87-
-r, --reference_package FILENAME
88-
Reference package to compare your package
89-
with. [required]
90-
-l, --legend Display the legend after the diff table
91-
-t, --test Exit with `0` if package can be safely
92-
imported. Else, returns the number of errors
93-
-a, --ascii Only use ASCII symbols to display results
94-
-b, --no_color Do not colorized the output
95-
-d, --diff PATH A folder where to generate unified diff
87+
-r, --reference_package FILENAME
88+
Reference package to compare your package
89+
with. [required]
90+
-l, --legend Display the legend after the diff table
91+
-t, --test Exit with `0` if package can be safely
92+
imported. Else, returns the number of errors
93+
-a, --ascii Only use ASCII symbols to display results
94+
-b, --no_color Do not colorized the output
95+
-d, --diff PATH A folder where to generate unified diff
96+
files output
97+
-e, --empty-config Check for values in the configuration
98+
elements: if so, exit with failure status.
99+
-h, --help Show this message and exit.
100+
96101

97102
.. _unified diff: https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html
98103

tox.ini

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ commands =
2626
vro-diff --help
2727
vro-diff --legend -r {toxinidir}/tests/data/package_v1.0.package {toxinidir}/tests/data/package_v1.1.package
2828
- vro-diff --test -r {toxinidir}/tests/data/package_v1.0.package {toxinidir}/tests/data/package_v1.1.package # || if [[ $? -eq 5 ]]; then true; else false; fi
29+
- vro-diff --empty-config -r {toxinidir}/tests/data/package_v1.0.package {toxinidir}/tests/data/package_v1.1.package # test empty configElements
2930
vro-diff -r {toxinidir}/tests/data/package_v1.0.package {toxinidir}/tests/data/package_v1.1.package -a # ASCII only
3031
vro-diff -r {toxinidir}/tests/data/package_v1.0.package {toxinidir}/tests/data/package_v1.1.package -b # Uncolorized
3132
vro-diff -r {toxinidir}/tests/data/package_v1.0.package {toxinidir}/tests/data/package_v1.1.package -d /tmp/testdiff/ # diff file generation

vro_package_diff/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@
1313
'vro_element',
1414
]
1515

16-
__version__ = "2.1.0"
16+
__version__ = "2.2.0"
1717
"""Define the version of the package.
1818
"""

vro_package_diff/__main__.py

+69-16
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,35 @@ def table_pprint(lists_of_items_by_state: dict, ascii: bool = False, colorized:
150150
print(SingleTable(data, title).table)
151151

152152

153+
def unexpected_values_pprint(lists_of_items_by_state: dict, ascii: bool = False):
154+
"""Generate and print a pretty table for output information.
155+
156+
Args:
157+
lists_of_items_by_state (dict of VROElementMetadata[]): A dict of items, stored by
158+
import state
159+
ascii (bool): Use ASCII for output or not? Defaults to False.
160+
colorized (bool, optional): Use color or not?. Defaults to True.
161+
"""
162+
if not lists_of_items_by_state['unexpected_values']:
163+
return
164+
data = []
165+
title = "Unexpected values in configurationElements"
166+
# Headers
167+
data.append(["ID", "Name", "Type", "Package", "Nb values"])
168+
for element in lists_of_items_by_state.get('unexpected_values', []):
169+
data.append([
170+
element.id,
171+
element.name,
172+
element.type,
173+
element.version,
174+
element.valued_items
175+
])
176+
if ascii:
177+
print("\n" + AsciiTable(data, title).table)
178+
else:
179+
print("\n" + SingleTable(data, title).table)
180+
181+
153182
def create_diff_file(src_elt: bytes, dst_elt: bytes, src_name: str, dst_name: str, diff_folder: str, state: str):
154183
"""Create a diff file between two versions of element data_content.
155184
@@ -188,7 +217,8 @@ def diff_vro_items(items_src,
188217
compared_package: str,
189218
ascii: bool = False,
190219
colorized: bool = True,
191-
diff_folder: bool = None):
220+
diff_folder: bool = None,
221+
empty_config: bool = True):
192222
"""Compare two vRO items lists.
193223
194224
Args:
@@ -205,7 +235,8 @@ def diff_vro_items(items_src,
205235
'upgrade': [],
206236
'conflict': [],
207237
'new': [],
208-
'unsupported': []
238+
'unsupported': [],
239+
'unexpected_values': []
209240
}
210241
for idst in items_dst:
211242
found = False
@@ -242,13 +273,17 @@ def diff_vro_items(items_src,
242273
if (not found) and (idst.type in SUPPORTED_ELEMENT_TYPES):
243274
logger.debug("%s is NOT IN source package" % idst)
244275
state = 'new'
276+
if idst.type == "ConfigurationElement" and empty_config:
277+
if idst.count_values_from_configuration_elt():
278+
lists_of_items_by_state['unexpected_values'].append(idst)
245279
lists_of_items_by_state[state].append(idst)
246280
logger.info("File A: %d elements" % len(items_src))
247281
logger.info("File B: %d elements" % len(items_dst))
248282
logger.info("Items to upgrade:\t\t%d" % len(lists_of_items_by_state['upgrade']))
249283
logger.info("Items without upgrade:\t%d" % len(lists_of_items_by_state['no_upgrade']))
250284
logger.info("Items in upgrade conflict:\t%d" % len(lists_of_items_by_state['conflict']))
251285
logger.info("New items:\t\t\t%d" % len(lists_of_items_by_state['new']))
286+
logger.info("ConfigurationElements with values:\t\t\t%d" % len(lists_of_items_by_state['unexpected_values']))
252287
logger.warning("Unsupported items:\t\t%d" % len(lists_of_items_by_state['unsupported']))
253288
total = (
254289
len(lists_of_items_by_state['unsupported'])
@@ -259,25 +294,37 @@ def diff_vro_items(items_src,
259294
)
260295
logger.info("Total items:\t\t\t%s" % total)
261296
table_pprint(lists_of_items_by_state, ascii=ascii, colorized=colorized)
262-
return len(lists_of_items_by_state['conflict'])
297+
return lists_of_items_by_state
263298

264299

265300
@click.command(context_settings=CLI_CONTEXT_SETTINGS)
266-
@click.option('-r',
267-
'--reference_package',
301+
@click.option('-r', '--reference_package',
268302
help="Reference package to compare your package with.",
269303
type=click.File('rb'),
270304
required=True)
271-
@click.argument('compared_package', type=click.File('rb'))
272-
@click.option('-l', '--legend', is_flag=True, help="Display the legend after the diff table")
273-
@click.option('-t', '--test', is_flag=True,
305+
@click.argument('compared_package',
306+
type=click.File('rb'))
307+
@click.option('-l', '--legend',
308+
is_flag=True,
309+
help="Display the legend after the diff table")
310+
@click.option('-t', '--test',
311+
is_flag=True,
274312
help="Exit with `0` if package can be safely imported. Else, returns the number of errors")
275-
@click.option('-a', '--ascii', is_flag=True, help="Only use ASCII symbols to display results")
276-
@click.option('-b', '--no_color', is_flag=True, help="Do not colorized the output")
277-
@click.option('-d', '--diff', help="A folder where to generate unified diff files output",
278-
type=click.Path(dir_okay=True, resolve_path=True))
313+
@click.option('-a', '--ascii',
314+
is_flag=True,
315+
help="Only use ASCII symbols to display results")
316+
@click.option('-b', '--no_color',
317+
is_flag=True,
318+
help="Do not colorized the output")
319+
@click.option('-d', '--diff',
320+
type=click.Path(dir_okay=True, resolve_path=True),
321+
help="A folder where to generate unified diff files output")
322+
@click.option('-e', '--empty-config',
323+
is_flag=True,
324+
help="Check for values in the configuration elements: if so, exit with failure status.")
279325
def cli(reference_package: str, compared_package: str, legend: bool = False,
280-
test: bool = False, ascii: bool = False, no_color: bool = False, diff: str = None):
326+
test: bool = False, ascii: bool = False, no_color: bool = False, diff: str = None,
327+
empty_config: bool = False):
281328
"""Compare two vRealize Orchestrator packages.
282329
283330
Use the [-r/--reference_package] option to specify the reference package.
@@ -287,7 +334,7 @@ def cli(reference_package: str, compared_package: str, legend: bool = False,
287334
logger.info("Reading items from the destination package")
288335
vro_items_dst = get_vroitems_from_package(compared_package)
289336
logger.info("Starting the comparison of both contents")
290-
exit_code = diff_vro_items(
337+
lists_of_items_by_state = diff_vro_items(
291338
vro_items_src,
292339
vro_items_dst,
293340
ascii=ascii,
@@ -302,10 +349,16 @@ def cli(reference_package: str, compared_package: str, legend: bool = False,
302349
if diff:
303350
logger.info("Unified diff files are stored in: %s" % diff)
304351
print("Unified diff files are stored in: %s" % diff)
352+
exit_code = 0
305353
if test:
306-
logger.info("Exiting with number of conflicts:" + str(exit_code))
307-
exit(exit_code)
354+
logger.info("Exiting with number of conflicts:" + str(len(lists_of_items_by_state['conflict'])))
355+
exit_code += len(lists_of_items_by_state['conflict'])
356+
if empty_config:
357+
unexpected_values_pprint(lists_of_items_by_state, ascii=ascii)
358+
logger.info("Exiting with number of values in configurationElements")
359+
exit_code += len(lists_of_items_by_state['unexpected_values'])
308360
logger.info("End of execution of the diff tool for vRO packages.")
361+
exit(exit_code)
309362

310363

311364
def main():

vro_package_diff/vro_element.py

+19
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def __init__(self, id: str, xml_info: bytes, data_content: bytes):
3030
self.type = None # populated with self.read_data later
3131
self.version = "0.0.0" # populated with self.read_data later
3232
self.dec_data_content = None # populated with self.read_data later
33+
self.valued_items = 0 # populated in count_values_from_configuration_elt later
3334
self.id = id
3435
self.type = self.get_item_type(xml_info)
3536
self.comp_version = None
@@ -116,3 +117,21 @@ def read_data(self):
116117
self.name = root.get('name')
117118
elif self.type == 'ConfigurationElement':
118119
self.name = root.find('display-name').text
120+
121+
def count_values_from_configuration_elt(self):
122+
"""Count the number of values found in a configurationElement.
123+
124+
Returns:
125+
int: number of values found in the configurationElement items.
126+
"""
127+
if not self.type == 'ConfigurationElement':
128+
logger.warn("Invalid type to count values in")
129+
return 0
130+
self.dec_data_content = self.u_decode_plain_content()
131+
root = Etree.fromstring(self.dec_data_content)
132+
atts = root.find('atts')
133+
for att in atts.findall('att'):
134+
if att.find('value') is not None:
135+
self.valued_items += 1
136+
logger.debug("Found %d values in %s" % (self.valued_items, self.name))
137+
return self.valued_items

0 commit comments

Comments
 (0)