提交 19cb82ce 编写于 作者: L Lukáš Doktor 提交者: Lucas Meneghel Rodrigues

avocado.core.plugins.multiplexer: Support for --tree view

Modify the --tree view to look like linux "tree" command and add support
to display content, inherited values or both.
Signed-off-by: NLukáš Doktor <ldoktor@redhat.com>
上级 9d20e6bf
......@@ -19,6 +19,7 @@ from .. import exit_codes
from .. import output
from .. import tree
from . import plugin
from ..settings import settings
class Multiplexer(plugin.Plugin):
......@@ -52,22 +53,23 @@ class Multiplexer(plugin.Plugin):
self.parser.add_argument('-s', '--system-wide', action='store_true',
help="Combine the files with the default "
"tree.")
self.parser.add_argument('-t', '--tree', action='store_true', default=False,
help='Shows the multiplex tree structure')
self.parser.add_argument('--attr', nargs='*', default=[],
help="Which attributes to show when using "
"--tree (default is 'name')")
self.parser.add_argument('-c', '--contents', action='store_true', default=False,
help="Shows the variant content (variables)")
self.parser.add_argument('-d', '--debug', action='store_true',
default=False, help="Debug multiplexed "
"files.")
self.parser.add_argument('-c', '--contents', action='store_true',
default=False, help="Shows the node content "
"(variables)")
self.parser.add_argument('--env', default=[], nargs='*',
help="Inject [path:]key:node values into "
"the final multiplex tree.")
env_parser = self.parser.add_argument_group("environment view options")
env_parser.add_argument('-d', '--debug', action='store_true',
default=False, help="Debug multiplexed "
"files.")
tree_parser = self.parser.add_argument_group("tree view options")
tree_parser.add_argument('-t', '--tree', action='store_true',
default=False, help='Shows the multiplex '
'tree structure')
tree_parser.add_argument('-i', '--inherit', action="store_true",
help="Show the inherited values")
super(Multiplexer, self).configure(self.parser)
self._from_args_tree = tree.TreeNode()
def activate(self, args):
# Extend default multiplex tree of --env values
......@@ -84,6 +86,15 @@ class Multiplexer(plugin.Plugin):
def run(self, args):
view = output.View(app_args=args)
err = None
if args.tree and args.debug:
err = "Option --tree is incompatible with --debug."
elif not args.tree and args.inherit:
err = "Option --inherit can be only used with --tree"
if err:
view.notify(event="minor", msg=self.parser.format_help())
view.notify(event="error", msg=err)
sys.exit(exit_codes.AVOCADO_FAIL)
try:
mux_tree = multiplexer.yaml2tree(args.multiplex_files,
args.filter_only, args.filter_out,
......@@ -96,9 +107,16 @@ class Multiplexer(plugin.Plugin):
mux_tree.merge(args.default_multiplex_tree)
mux_tree.merge(self._from_args_tree)
if args.tree:
view.notify(event='message', msg='Config file tree structure:')
view.notify(event='minor',
msg=mux_tree.get_ascii(attributes=args.attr))
if args.contents:
verbose = 1
else:
verbose = 0
if args.inherit:
verbose += 2
use_utf8 = settings.get_value("runner.output", "utf8",
key_type=bool, default=None)
view.notify(event='minor', msg=tree.tree_view(mux_tree, verbose,
use_utf8))
sys.exit(exit_codes.AVOCADO_ALL_OK)
variants = multiplexer.MuxTree(mux_tree)
......
......@@ -35,6 +35,7 @@ original base tree code and re-license under GPLv2+, given that GPLv3 and GPLv2
import collections
import itertools
import locale
import os
import re
......@@ -295,72 +296,6 @@ class TreeNode(object):
""" Get list of leaf nodes """
return list(self.iter_leaves())
def get_ascii(self, show_internal=True, compact=False, attributes=None):
"""
Get ascii-art tree structure
:param show_internal: Show intermediary nodes
:param compact: Compress the tree vertically
:param attributes: List of node attributes to be printed out ['name']
:return: string
"""
(lines, _) = self.ascii_art(show_internal=show_internal,
compact=compact, attributes=attributes)
return '\n' + '\n'.join(lines)
def ascii_art(self, char1='-', show_internal=True, compact=False,
attributes=None):
"""
Generate ascii-art for this node
:param char1: Incomming path character [-]
:param show_internal: Show intermediary nodes
:param compact: Compress the tree vertically
:param attributes: List of node attributes to be printed out ['name']
:return: list of strings
"""
if not attributes:
attributes = ["name"]
node_name = ', '.join(map(str, [getattr(self, v)
for v in attributes
if hasattr(self, v)]))
if self.multiplex:
node_name += "-<>"
length = max(2, (len(node_name) + 1) if not self.children or show_internal else 3)
pad = ' ' * length
_pad = ' ' * (length - 1)
if not self.is_leaf:
mids = []
result = []
for char in self.children:
if len(self.children) == 1:
char2 = '-'
elif char is self.children[0]:
char2 = '/'
elif char is self.children[-1]:
char2 = '\\'
else:
char2 = '-'
(clines, mid) = char.ascii_art(char2, show_internal, compact,
attributes)
mids.append(mid + len(result))
result.extend(clines)
if not compact:
result.append('')
if not compact:
result.pop()
(low, high, end) = (mids[0], mids[-1], len(result))
prefixes = ([pad] * (low + 1) + [_pad + '|'] * (high - low - 1) +
[pad] * (end - high))
mid = (low + high) / 2
prefixes[mid] = char1 + '-' * (length - 2) + prefixes[mid][-1]
result = [p + l for (p, l) in zip(prefixes, result)]
if show_internal:
stem = result[mid]
result[mid] = stem[0] + node_name + stem[len(node_name) + 1:]
return result, mid
else:
return [char1 + '-' + node_name], 0
def detach(self):
""" Detach this node from parent """
if self.parent:
......@@ -723,3 +658,114 @@ def get_named_tree_cls(path):
children,
path.split(':', 1)[-1])
return NamedTreeNodeDebug
def tree_view(root, verbose=None, use_utf8=None):
"""
Generate tree-view of the given node
:param root: root node
:param verbose: verbosity (0, 1, 2, 3)
:param use_utf8: Use utf-8 encoding (None=autodetect)
:return: string representing this node's tree structure
"""
def prefixed_write(prefix1, prefix2, value):
"""
Split value's lines and prepend empty prefix to 2nd+ lines
:return: list of lines
"""
value = str(value)
if '\n' not in value:
return [prefix1 + prefix2 + value]
value = value.splitlines()
empty_prefix2 = ' ' * len(prefix2)
return [prefix1 + prefix2 + value[0]] + [prefix1 + empty_prefix2 +
_ for _ in value[1:]]
def process_node(node):
"""
Generate this node's tree-view
:return: list of lines
"""
if node.multiplex:
down = charset['DoubleDown']
down_right = charset['DoubleDownRight']
right = charset['DoubleRight']
else:
down = charset['Down']
down_right = charset['DownRight']
right = charset['Right']
out = [node.name]
if verbose >= 2 and node.is_leaf:
values = node.environment.iteritems()
elif verbose in (1, 3):
values = node.value.iteritems()
else:
values = None
if values:
val = charset['Value']
if node.children:
val_prefix = down
else:
val_prefix = ' '
for key, value in values:
out.extend(prefixed_write(val_prefix, val + key + ': ',
value))
if node.children:
for child in node.children[:-1]:
lines = process_node(child)
out.append(down_right + lines[0])
out.extend(down + line for line in lines[1:])
lines = process_node(node.children[-1])
out.append(right + lines[0])
empty_down_right = ' ' * len(down_right)
out.extend(empty_down_right + line for line in lines[1:])
return out
if use_utf8 is None:
use_utf8 = locale.getdefaultlocale()[1] == 'UTF-8'
if use_utf8:
charset = {'DoubleDown': u' \u2551 ',
'DoubleDownRight': u' \u2560\u2550\u2550 ',
'DoubleRight': u' \u255a\u2550\u2550 ',
'Down': u' \u2503 ',
'DownRight': u' \u2523\u2501\u2501 ',
'Right': u' \u2517\u2501\u2501 ',
'Value': u'\u2192 '}
else: # ASCII fallback
charset = {'Down': ' | ',
'DownRight': ' |-- ',
'Right': ' \\-- ',
'DoubleDown': ' # ',
'DoubleDownRight': ' #== ',
'DoubleRight': ' #== ',
'Value': ' -> '}
if root.multiplex:
down = charset['DoubleDown']
down_right = charset['DoubleDownRight']
right = charset['DoubleRight']
else:
down = charset['Down']
down_right = charset['DownRight']
right = charset['Right']
out = []
if (verbose >= 2) and root.is_leaf:
values = root.environment.iteritems()
elif verbose in (1, 3):
values = root.value.iteritems()
else:
values = None
if values:
prefix = charset['Value'].lstrip()
for key, value in values:
out.extend(prefixed_write(prefix, key + ': ', value))
if root.children:
for child in root.children[:-1]:
lines = process_node(child)
out.append(down_right + lines[0])
out.extend(down + line for line in lines[1:])
lines = process_node(root.children[-1])
out.append(right + lines[0])
out.extend(' ' * len(down_right) + line for line in lines[1:])
# When not on TTY we need to force the encoding
return '\n'.join(out).encode('utf-8' if use_utf8 else 'ascii')
......@@ -27,6 +27,8 @@ profilers = /etc/avocado/sysinfo/profilers
[runner.output]
# Whether to display colored output in terminals that support it
colored = True
# Use utf8 encoding (True, False, None=autodetect)
utf8 =
[runner.behavior]
# Keep job temporary files after jobs (useful for avocado debugging)
......
......@@ -112,7 +112,7 @@ class TestTree(unittest.TestCase):
'prod']
self.assertEqual(leaves, self.tree.get_leaves())
# asci contain all leaves and doesn't raise any exceptions
ascii = self.tree.get_ascii()
ascii = tree.tree_view(self.tree, 0, False)
for leaf in leaves:
self.assertIn(leaf, ascii, "Leaf %s not in asci:\n%s"
% (leaf, ascii))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册