tools/qvm-ls: kill fixed column width
Calculate column width dynamically, besed on actual contents.
This commit is contained in:
parent
fea3d3391f
commit
435a465d70
@ -497,7 +497,7 @@ class VmNameGroup(argparse._MutuallyExclusiveGroup):
|
|||||||
self.add_argument('VMNAME', action=vm_action, nargs='*', default=[])
|
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.
|
''' Uses the unix column command to print pretty table.
|
||||||
|
|
||||||
:param str text: list of lists/sets
|
: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'.join([unit_separator.join(row) for row in table])
|
||||||
text_table += '\n'
|
text_table += '\n'
|
||||||
|
|
||||||
|
if stream is None:
|
||||||
|
stream = sys.stdout
|
||||||
|
|
||||||
# for tests...
|
# for tests...
|
||||||
if sys.stdout != sys.__stdout__:
|
if stream != sys.__stdout__:
|
||||||
p = subprocess.Popen(cmd + ['-c', '80'], stdin=subprocess.PIPE,
|
p = subprocess.Popen(cmd + ['-c', '80'], stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE)
|
stdout=subprocess.PIPE)
|
||||||
p.stdin.write(text_table.encode())
|
p.stdin.write(text_table.encode())
|
||||||
(out, _) = p.communicate()
|
(out, _) = p.communicate()
|
||||||
sys.stdout.write(out.decode())
|
stream.write(out.decode())
|
||||||
else:
|
else:
|
||||||
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
|
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
|
||||||
p.communicate(text_table.encode())
|
p.communicate(text_table.encode())
|
||||||
|
@ -41,11 +41,10 @@ import qubesmgmt.vm
|
|||||||
#
|
#
|
||||||
|
|
||||||
class Column(object):
|
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.
|
to fetch a parameter describing the domain.
|
||||||
|
|
||||||
:param str head: Column head (usually uppercase).
|
:param str head: Column head (usually uppercase).
|
||||||
:param int width: Column width.
|
|
||||||
:param str attr: Attribute, possibly complex (containing ``.``). This may \
|
:param str attr: Attribute, possibly complex (containing ``.``). This may \
|
||||||
also be a callable that gets as its only argument the domain.
|
also be a callable that gets as its only argument the domain.
|
||||||
:param str doc: Description of column (will be visible in --help-columns).
|
:param str doc: Description of column (will be visible in --help-columns).
|
||||||
@ -54,9 +53,8 @@ class Column(object):
|
|||||||
#: collection of all columns
|
#: collection of all columns
|
||||||
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_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)
|
self.__doc__ = doc if doc is None else qubesmgmt.utils.format_doc(doc)
|
||||||
|
|
||||||
# intentionally not always do set self._attr,
|
# intentionally not always do set self._attr,
|
||||||
@ -77,12 +75,12 @@ class Column(object):
|
|||||||
:py:meth:`Column.format` method instead.
|
:py:meth:`Column.format` method instead.
|
||||||
|
|
||||||
:param qubes.vm.qubesvm.QubesVM: Domain to get a value from.
|
: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
|
:rtype: str
|
||||||
'''
|
'''
|
||||||
|
|
||||||
value = self.format(vm) or '-'
|
value = self.format(vm) or '-'
|
||||||
return value.ljust(self.ls_width)
|
return value
|
||||||
|
|
||||||
|
|
||||||
def format(self, vm):
|
def format(self, vm):
|
||||||
@ -117,8 +115,8 @@ class Column(object):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '{}(head={!r}, width={!r})'.format(self.__class__.__name__,
|
return '{}(head={!r})'.format(self.__class__.__name__,
|
||||||
self.ls_head, self.ls_width)
|
self.ls_head)
|
||||||
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
@ -200,7 +198,6 @@ class StatusColumn(Column):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(StatusColumn, self).__init__(
|
super(StatusColumn, self).__init__(
|
||||||
head='STATUS',
|
head='STATUS',
|
||||||
width=len(self.get_flags()) + 1,
|
|
||||||
doc=self.__class__.__doc__)
|
doc=self.__class__.__doc__)
|
||||||
|
|
||||||
|
|
||||||
@ -337,41 +334,41 @@ def calc_used(vm, volume_name):
|
|||||||
|
|
||||||
# todo maxmem
|
# todo maxmem
|
||||||
|
|
||||||
Column('GATEWAY', width=15,
|
Column('GATEWAY',
|
||||||
attr='netvm.gateway',
|
attr='netvm.gateway',
|
||||||
doc='Network gateway.')
|
doc='Network gateway.')
|
||||||
|
|
||||||
Column('MEMORY', width=5,
|
Column('MEMORY',
|
||||||
attr=(lambda vm: vm.get_mem() / 1024 if vm.is_running() else None),
|
attr=(lambda vm: vm.get_mem() / 1024 if vm.is_running() else None),
|
||||||
doc='Memory currently used by VM')
|
doc='Memory currently used by VM')
|
||||||
|
|
||||||
Column('DISK', width=5,
|
Column('DISK',
|
||||||
attr=(lambda vm: vm.storage.get_disk_utilization() / 1024 / 1024),
|
attr=(lambda vm: vm.storage.get_disk_utilization() / 1024 / 1024),
|
||||||
doc='Total disk utilisation.')
|
doc='Total disk utilisation.')
|
||||||
|
|
||||||
|
|
||||||
Column('PRIV-CURR', width=5,
|
Column('PRIV-CURR',
|
||||||
attr=(lambda vm: calc_usage(vm, 'private')),
|
attr=(lambda vm: calc_usage(vm, 'private')),
|
||||||
doc='Disk utilisation by private image (/home, /usr/local).')
|
doc='Disk utilisation by private image (/home, /usr/local).')
|
||||||
|
|
||||||
Column('PRIV-MAX', width=5,
|
Column('PRIV-MAX',
|
||||||
attr=(lambda vm: calc_size(vm, 'private')),
|
attr=(lambda vm: calc_size(vm, 'private')),
|
||||||
doc='Maximum available space for private image.')
|
doc='Maximum available space for private image.')
|
||||||
|
|
||||||
Column('PRIV-USED', width=5,
|
Column('PRIV-USED',
|
||||||
attr=(lambda vm: calc_used(vm, 'private')),
|
attr=(lambda vm: calc_used(vm, 'private')),
|
||||||
doc='Disk utilisation by private image as a percentage of available space.')
|
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')),
|
attr=(lambda vm: calc_usage(vm, 'root')),
|
||||||
doc='Disk utilisation by root image (/usr, /lib, /etc, ...).')
|
doc='Disk utilisation by root image (/usr, /lib, /etc, ...).')
|
||||||
|
|
||||||
Column('ROOT-MAX', width=5,
|
Column('ROOT-MAX',
|
||||||
attr=(lambda vm: calc_size(vm, 'root')),
|
attr=(lambda vm: calc_size(vm, 'root')),
|
||||||
doc='Maximum available space for root image.')
|
doc='Maximum available space for root image.')
|
||||||
|
|
||||||
Column('ROOT-USED', width=5,
|
Column('ROOT-USED',
|
||||||
attr=(lambda vm: calc_used(vm, 'root')),
|
attr=(lambda vm: calc_used(vm, 'root')),
|
||||||
doc='Disk utilisation by root image as a percentage of available space.')
|
doc='Disk utilisation by root image as a percentage of available space.')
|
||||||
|
|
||||||
@ -391,21 +388,13 @@ class Table(object):
|
|||||||
self.raw_data = raw_data
|
self.raw_data = raw_data
|
||||||
|
|
||||||
|
|
||||||
def format_head(self):
|
def get_head(self):
|
||||||
'''Format table head (all column heads).'''
|
'''Get table head data (all column heads).'''
|
||||||
return ''.join('{head:{width}s}'.format(
|
return [col.ls_head for col in self.columns]
|
||||||
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_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):
|
def write_table(self, stream=sys.stdout):
|
||||||
'''Write whole table to file-like object.
|
'''Write whole table to file-like object.
|
||||||
@ -413,10 +402,15 @@ class Table(object):
|
|||||||
:param file stream: Stream to write the table to.
|
:param file stream: Stream to write the table to.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
table_data = []
|
||||||
if not self.raw_data:
|
if not self.raw_data:
|
||||||
stream.write(self.format_head() + '\n')
|
table_data.append(self.get_head())
|
||||||
for vm in self.app.domains:
|
for vm in self.app.domains:
|
||||||
stream.write(self.format_row(vm) + '\n')
|
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.
|
#: Available formats. Feel free to plug your own one.
|
||||||
|
Loading…
Reference in New Issue
Block a user