From 4c654465461d48abfeae7115c9d6691f70de1751 Mon Sep 17 00:00:00 2001 From: adrian-turjak Date: Mon, 29 Aug 2016 15:58:23 +1200 Subject: [PATCH] Fixing client format and sort issues Client now doesn't sort by default and instead expects sorting to come from the server. Json formatting has been improved to correctly wrap for long lines. Added json formatter for newly added 'approved_by' field. This will still work for older deployments without the approved_by field. Change-Id: I18adcccc36c9f71af8d4c90aacafdb5793e4999e --- stacktaskclient/common/utils.py | 77 ++++++++++++++++++-- stacktaskclient/openstack/common/cliutils.py | 2 +- stacktaskclient/v1/shell.py | 3 +- 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/stacktaskclient/common/utils.py b/stacktaskclient/common/utils.py index 346eb1e..810fa2f 100644 --- a/stacktaskclient/common/utils.py +++ b/stacktaskclient/common/utils.py @@ -14,10 +14,15 @@ # under the License. import base64 +from fcntl import ioctl import logging import os import textwrap import uuid +import six +import struct +import sys +import termios from oslo_serialization import jsonutils from oslo_utils import importutils @@ -64,9 +69,26 @@ def resource_nested_identifier(rsrc): return "/".join(nested_identifier) -def json_formatter(js): - return jsonutils.dumps(js, indent=2, ensure_ascii=False, - separators=(', ', ': ')) +def json_formatter(js, wrap=None): + value = jsonutils.dumps(js, indent=2, ensure_ascii=False, + separators=(', ', ': ')) + # as json sort of does it's own line splitting, we have to check + # if each line is over the wrap limit, and split ourselves. + if wrap: + lines = [] + for line in value.split('\n'): + if len(line) > wrap: + lines.append(line[0:wrap-1]) + line = line[wrap:] + while line: + lines.append(line[0:wrap-1]) + line = line[wrap:] + else: + lines.append(line) + value = "" + for line in lines: + value += "%s\n" % line + return value def text_wrap_formatter(d): @@ -77,7 +99,22 @@ def newline_list_formatter(r): return '\n'.join(r or []) -def print_dict(d, formatters=None): +def print_dict(d, formatters=None, wrap=None): + if not wrap: + # 2 columns padded by 1 on each side = 4 + # 3 x '|' as border and separator = 3 + # total non-content padding = 7 + padding = 7 + # Now we need to find what the longest key is + longest_key = 0 + for key in d.keys(): + if len(key) > longest_key: + longest_key = len(key) + # the wrap for the value column is based on + # what is left after we account for the padding + # and longest key + wrap = terminal_width() - padding - longest_key + formatters = formatters or {} pt = prettytable.PrettyTable(['Property', 'Value'], caching=False, print_empty=False) @@ -85,9 +122,11 @@ def print_dict(d, formatters=None): for field in d.keys(): if field in formatters: - pt.add_row([field, formatters[field](d[field])]) + value = formatters[field](d[field], wrap) + pt.add_row([field, value]) else: - pt.add_row([field, d[field]]) + value = textwrap.fill(six.text_type(d[field]), wrap) + pt.add_row([field, value]) print(pt.get_string(sortby='Property')) @@ -278,3 +317,29 @@ def get_response_body(resp): else: body = None return body + + +def terminal_width(): + if hasattr(os, 'get_terminal_size'): + # python 3.3 onwards has built-in support for getting terminal size + try: + return os.get_terminal_size().columns + except OSError: + return None + try: + # winsize structure has 4 unsigned short fields + winsize = b'\0' * struct.calcsize('hhhh') + try: + winsize = ioctl(sys.stdout, termios.TIOCGWINSZ, winsize) + except IOError: + return None + except TypeError: + # this is raised in unit tests as stdout is sometimes a StringIO + return None + winsize = struct.unpack('hhhh', winsize) + columns = winsize[1] + if not columns: + return None + return columns + except IOError: + return None diff --git a/stacktaskclient/openstack/common/cliutils.py b/stacktaskclient/openstack/common/cliutils.py index c642256..3303706 100644 --- a/stacktaskclient/openstack/common/cliutils.py +++ b/stacktaskclient/openstack/common/cliutils.py @@ -138,7 +138,7 @@ def isunauthenticated(func): return getattr(func, 'unauthenticated', False) -def print_list(objs, fields, formatters=None, sortby_index=0, +def print_list(objs, fields, formatters=None, sortby_index=None, mixed_case_fields=None, field_labels=None): """Print a list or objects as a table, one row per object. diff --git a/stacktaskclient/v1/shell.py b/stacktaskclient/v1/shell.py index b93724c..435de92 100644 --- a/stacktaskclient/v1/shell.py +++ b/stacktaskclient/v1/shell.py @@ -53,7 +53,8 @@ def do_task_show(sc, args): formatters = { 'actions': utils.json_formatter, 'action_notes': utils.json_formatter, - 'keystone_user': utils.json_formatter + 'keystone_user': utils.json_formatter, + 'approved_by': utils.json_formatter } utils.print_dict(task.to_dict(), formatters=formatters) except exc.HTTPNotFound: