From 435a465d7046128699188ea81d9ce4689931c26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Sat, 11 Mar 2017 01:47:12 +0100 Subject: [PATCH] tools/qvm-ls: kill fixed column width Calculate column width dynamically, besed on actual contents. --- qubesmgmt/tools/__init__.py | 9 ++++-- qubesmgmt/tools/qvm_ls.py | 64 +++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/qubesmgmt/tools/__init__.py b/qubesmgmt/tools/__init__.py index 8a3be8f..92f62a1 100644 --- a/qubesmgmt/tools/__init__.py +++ b/qubesmgmt/tools/__init__.py @@ -497,7 +497,7 @@ class VmNameGroup(argparse._MutuallyExclusiveGroup): self.add_argument('VMNAME', action=vm_action, nargs='*', default=[]) -def print_table(table): +def print_table(table, stream=None): ''' Uses the unix column command to print pretty table. :param str text: list of lists/sets @@ -507,13 +507,16 @@ def print_table(table): text_table = '\n'.join([unit_separator.join(row) for row in table]) text_table += '\n' + if stream is None: + stream = sys.stdout + # for tests... - if sys.stdout != sys.__stdout__: + if stream != sys.__stdout__: p = subprocess.Popen(cmd + ['-c', '80'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) p.stdin.write(text_table.encode()) (out, _) = p.communicate() - sys.stdout.write(out.decode()) + stream.write(out.decode()) else: p = subprocess.Popen(cmd, stdin=subprocess.PIPE) p.communicate(text_table.encode()) diff --git a/qubesmgmt/tools/qvm_ls.py b/qubesmgmt/tools/qvm_ls.py index 051ac89..0bc7af3 100644 --- a/qubesmgmt/tools/qvm_ls.py +++ b/qubesmgmt/tools/qvm_ls.py @@ -41,11 +41,10 @@ import qubesmgmt.vm # class Column(object): - '''A column in qvm-ls output characterised by its head, a width and a way + '''A column in qvm-ls output characterised by its head and a way to fetch a parameter describing the domain. :param str head: Column head (usually uppercase). - :param int width: Column width. :param str attr: Attribute, possibly complex (containing ``.``). This may \ also be a callable that gets as its only argument the domain. :param str doc: Description of column (will be visible in --help-columns). @@ -54,9 +53,8 @@ class Column(object): #: collection of all columns columns = {} - def __init__(self, head, width=0, attr=None, doc=None): + def __init__(self, head, attr=None, doc=None): self.ls_head = head - self.ls_width = max(width, len(self.ls_head) + 1) self.__doc__ = doc if doc is None else qubesmgmt.utils.format_doc(doc) # intentionally not always do set self._attr, @@ -77,12 +75,12 @@ class Column(object): :py:meth:`Column.format` method instead. :param qubes.vm.qubesvm.QubesVM: Domain to get a value from. - :returns: string that is at least as wide as needed to fill table row. + :returns: string to display :rtype: str ''' value = self.format(vm) or '-' - return value.ljust(self.ls_width) + return value def format(self, vm): @@ -117,8 +115,8 @@ class Column(object): return ret def __repr__(self): - return '{}(head={!r}, width={!r})'.format(self.__class__.__name__, - self.ls_head, self.ls_width) + return '{}(head={!r})'.format(self.__class__.__name__, + self.ls_head) def __eq__(self, other): @@ -200,7 +198,6 @@ class StatusColumn(Column): def __init__(self): super(StatusColumn, self).__init__( head='STATUS', - width=len(self.get_flags()) + 1, doc=self.__class__.__doc__) @@ -337,41 +334,41 @@ def calc_used(vm, volume_name): # todo maxmem -Column('GATEWAY', width=15, +Column('GATEWAY', attr='netvm.gateway', doc='Network gateway.') -Column('MEMORY', width=5, +Column('MEMORY', attr=(lambda vm: vm.get_mem() / 1024 if vm.is_running() else None), doc='Memory currently used by VM') -Column('DISK', width=5, +Column('DISK', attr=(lambda vm: vm.storage.get_disk_utilization() / 1024 / 1024), doc='Total disk utilisation.') -Column('PRIV-CURR', width=5, +Column('PRIV-CURR', attr=(lambda vm: calc_usage(vm, 'private')), doc='Disk utilisation by private image (/home, /usr/local).') -Column('PRIV-MAX', width=5, +Column('PRIV-MAX', attr=(lambda vm: calc_size(vm, 'private')), doc='Maximum available space for private image.') -Column('PRIV-USED', width=5, +Column('PRIV-USED', attr=(lambda vm: calc_used(vm, 'private')), doc='Disk utilisation by private image as a percentage of available space.') -Column('ROOT-CURR', width=5, +Column('ROOT-CURR', attr=(lambda vm: calc_usage(vm, 'root')), doc='Disk utilisation by root image (/usr, /lib, /etc, ...).') -Column('ROOT-MAX', width=5, +Column('ROOT-MAX', attr=(lambda vm: calc_size(vm, 'root')), doc='Maximum available space for root image.') -Column('ROOT-USED', width=5, +Column('ROOT-USED', attr=(lambda vm: calc_used(vm, 'root')), doc='Disk utilisation by root image as a percentage of available space.') @@ -391,21 +388,13 @@ class Table(object): self.raw_data = raw_data - def format_head(self): - '''Format table head (all column heads).''' - return ''.join('{head:{width}s}'.format( - head=col.ls_head, width=col.ls_width) - for col in self.columns[:-1]) + \ - self.columns[-1].ls_head - - - def format_row(self, vm): - '''Format single table row (all columns for one domain).''' - if self.raw_data: - return '|'.join(col.format(vm) for col in self.columns) - else: - return ''.join(col.cell(vm) for col in self.columns) + def get_head(self): + '''Get table head data (all column heads).''' + return [col.ls_head for col in self.columns] + def get_row(self, vm): + '''Get single table row data (all columns for one domain).''' + return [col.cell(vm) for col in self.columns] def write_table(self, stream=sys.stdout): '''Write whole table to file-like object. @@ -413,10 +402,15 @@ class Table(object): :param file stream: Stream to write the table to. ''' + table_data = [] if not self.raw_data: - stream.write(self.format_head() + '\n') - for vm in self.app.domains: - stream.write(self.format_row(vm) + '\n') + table_data.append(self.get_head()) + for vm in self.app.domains: + table_data.append(self.get_row(vm)) + qubesmgmt.tools.print_table(table_data, stream=stream) + else: + for vm in self.app.domains: + stream.write('|'.join(self.get_row(vm)) + '\n') #: Available formats. Feel free to plug your own one.