qubes/tools: add qubes-prefs

fixes QubesOS/qubes-issues#1209
This commit is contained in:
Wojtek Porczyk 2015-12-24 00:28:52 +01:00
parent 87f74a5ba8
commit 7b30361fa6
5 changed files with 202 additions and 41 deletions

View File

@ -1,8 +1,55 @@
.. program:: qubes-prefs
:program:`qubes-prefs` -- List/set various global properties
============================================================
:program:`qubes-prefs` -- Display system-wide Qubes settings
============================================================
Synopsis
--------
:command:`qubes-prefs` [-h] [--xml *XMLFILE*] [--verbose] [--quiet] [--force-root] [--help-properties] [*PROPERTY* [*VALUE*\|--delete]]
Options
-------
.. option:: --help, -h
Show help message and exit.
.. option:: --help-properties
List available properties with short descriptions and exit.
.. option:: --qubesxml=XMLFILE
Qubes OS store file.
.. option:: --verbose, -v
Increase verbosity.
.. option:: --quiet, -q
Decrease verbosity.
.. option:: --force-root
Force to run as root.
.. option:: --unset, --default, --delete, -D
Unset the property. If is has default value, it will be used instead.
Common properties
=================
This list is non-exhaustive. For authoritative listing, see
:option:`--help-properties` and documentation of the source code.
.. warning::
This list is from the core2. It is wrong in many cases, some of them obvious,
some of them not.
- clock VM
- update VM
@ -11,12 +58,12 @@
- default kernel
- default netVM
Synopsis
========
:command:`qubes-prefs`
Authors
=======
-------
| Joanna Rutkowska <joanna at invisiblethingslab dot com>
| Rafal Wojtczuk <rafal at invisiblethingslab dot com>
| Marek Marczykowski <marmarek at invisiblethingslab dot com>
| Wojtek Porczyk <woju at invisiblethingslab dot com>
.. vim: ts=3 sw=3 et tw=80

View File

@ -86,6 +86,47 @@ class SinglePropertyAction(argparse.Action):
if self.const is None else self.const
class HelpPropertiesAction(argparse.Action):
'''Action for argument parser that displays all properties and exits.'''
# pylint: disable=redefined-builtin,too-few-public-methods
def __init__(self,
option_strings,
klass=None,
dest=argparse.SUPPRESS,
default=argparse.SUPPRESS,
help='list all available properties with short descriptions'
' and exit'):
super(HelpPropertiesAction, self).__init__(
option_strings=option_strings,
dest=dest,
default=default,
nargs=0,
help=help)
# late import because of circular dependency
import qubes
self._klass = klass if klass is not None else qubes.Qubes
def __call__(self, parser, namespace, values, option_string=None):
# pylint: disable=redefined-outer-name
properties = self._klass.property_list()
width = max(len(prop.__name__) for prop in properties)
wrapper = textwrap.TextWrapper(width=80,
initial_indent=' ', subsequent_indent=' ' * (width + 6))
text = 'Common properties:\n' + '\n'.join(
wrapper.fill('{name:{width}s} {doc}'.format(
name=prop.__name__,
doc=qubes.utils.format_doc(prop.__doc__) if prop.__doc__ else'',
width=width))
for prop in sorted(properties))
if self._klass is not qubes.Qubes:
text += '\n\n' \
'There may be more properties in specific domain classes.\n'
parser.exit(message=text)
class QubesArgumentParser(argparse.ArgumentParser):
'''Parser preconfigured for use in most of the Qubes command-line tools.

103
qubes/tools/qubes_prefs.py Normal file
View File

@ -0,0 +1,103 @@
#!/usr/bin/python2
# -*- encoding: utf8 -*-
#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2010-2015 Joanna Rutkowska <joanna@invisiblethingslab.com>
# Copyright (C) 2015 Wojtek Porczyk <woju@invisiblethingslab.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# TODO merge printing with qvm-prefs
# TODO list only non-default properties
from __future__ import print_function
import argparse
import sys
import textwrap
import qubes
import qubes.tools
import qubes.utils
parser = qubes.tools.QubesArgumentParser(
want_force_root=True)
parser.add_argument('--help-properties',
action=qubes.tools.HelpPropertiesAction)
parser.add_argument('property', metavar='PROPERTY',
nargs='?',
help='name of the property to show or change')
parser_value = parser.add_mutually_exclusive_group()
parser_value.add_argument('value', metavar='VALUE',
nargs='?',
help='new value of the property')
parser.add_argument('--unset', '--default', '--delete', '-D',
dest='delete',
action='store_true',
help='unset the property; if property has default value, it will be used'
' instead')
def main():
args = parser.parse_args()
if args.property is None:
properties = args.app.property_list()
width = max(len(prop.__name__) for prop in properties)
for prop in sorted(properties):
try:
value = getattr(args.app, prop.__name__)
except AttributeError:
print('{name:{width}s} U'.format(
name=prop.__name__, width=width))
continue
if args.app.property_is_default(prop):
print('{name:{width}s} D {value!r}'.format(
name=prop.__name__, width=width, value=value))
else:
print('{name:{width}s} - {value!r}'.format(
name=prop.__name__, width=width, value=value))
return True
if args.value is not None:
setattr(args.app, args.property, args.value)
args.app.save()
return True
if args.delete:
delattr(args.app, args.property)
args.app.save()
return True
print(str(getattr(args.app, args.property)))
return True
if __name__ == '__main__':
sys.exit(not main())

View File

@ -36,44 +36,13 @@ import qubes.utils
import qubes.vm
class _HelpPropertiesAction(argparse.Action):
'''Action for argument parser that displays all properties and exits.'''
# pylint: disable=redefined-builtin,too-few-public-methods
def __init__(self,
option_strings,
dest=argparse.SUPPRESS,
default=argparse.SUPPRESS,
help='list all available properties with short descriptions'
' and exit'):
super(_HelpPropertiesAction, self).__init__(
option_strings=option_strings,
dest=dest,
default=default,
nargs=0,
help=help)
def __call__(self, parser, namespace, values, option_string=None):
# pylint: disable=redefined-outer-name
properties = qubes.vm.qubesvm.QubesVM.property_list()
width = max(len(prop.__name__) for prop in properties)
wrapper = textwrap.TextWrapper(width=80,
initial_indent=' ', subsequent_indent=' ' * (width + 6))
text = 'Common properties:\n' + '\n'.join(
wrapper.fill('{name:{width}s} {doc}'.format(
name=prop.__name__,
doc=qubes.utils.format_doc(prop.__doc__) if prop.__doc__ else'',
width=width))
for prop in sorted(properties))
parser.exit(message=text
+ '\n\nThere may be more properties in specific domain classes.\n')
parser = qubes.tools.QubesArgumentParser(
want_force_root=True,
want_vm=True)
parser.add_argument('--help-properties', action=_HelpPropertiesAction)
parser.add_argument('--help-properties',
action=qubes.tools.HelpPropertiesAction,
klass=qubes.vm.qubesvm.QubesVM)
parser.add_argument('property', metavar='PROPERTY',
nargs='?',

View File

@ -232,6 +232,7 @@ fi
%{python_sitelib}/qubes/tools/__init__.py*
%{python_sitelib}/qubes/tools/qmemmand.py*
%{python_sitelib}/qubes/tools/qubes_create.py*
%{python_sitelib}/qubes/tools/qubes_prefs.py*
%{python_sitelib}/qubes/tools/qvm_create.py*
%{python_sitelib}/qubes/tools/qvm_kill.py*
%{python_sitelib}/qubes/tools/qvm_ls.py*