From ba2da174de98f0197000e24007f58562f1c20bcc Mon Sep 17 00:00:00 2001 From: Ali Mirjamali Date: Tue, 22 Oct 2024 16:56:47 +0330 Subject: [PATCH] Add UNIX wildcards support Allowing user to select qubes using UNIX like wildcards --- qubesadmin/tests/tools/qvm_ls.py | 40 ++++++++++++++++++++++++++++++++ qubesadmin/tools/__init__.py | 15 ++++++++++-- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/qubesadmin/tests/tools/qvm_ls.py b/qubesadmin/tests/tools/qvm_ls.py index 81d37567..518a4a54 100644 --- a/qubesadmin/tests/tools/qvm_ls.py +++ b/qubesadmin/tests/tools/qvm_ls.py @@ -129,6 +129,46 @@ def test_103_list_all(self): 'dom0 Running TestVM - - -\n' 'test-vm Running TestVM - - -\n') + def test_104_wildcards(self): + app = TestApp() + app.domains = TestVMCollection( + [ + ('dom0', TestVM('dom0')), + ('debian-13', TestVM('debian-13')), + ('debian-13-minimal', TestVM('debian-13-minimal')), + ('debian-13-xfce', TestVM('debian-13-xfce')), + ('debian-sid', TestVM('debian-sid')), + ('fedora-41', TestVM('fedora-41')), + ('fedora-41-minimal', TestVM('fedora-41-minimal')), + ('fedora-41-xfce', TestVM('fedora-41-xfce')), + ('fedora-rawhide', TestVM('fedora-rawhide')), + ] + ) + with qubesadmin.tests.tools.StdoutBuffer() as stdout: + qubesadmin.tools.qvm_ls.main(['--raw-list', 'fedora*'], app=app) + self.assertEqual(stdout.getvalue(), + 'fedora-41\nfedora-41-minimal\nfedora-41-xfce\nfedora-rawhide\n') + + with qubesadmin.tests.tools.StdoutBuffer() as stdout: + qubesadmin.tools.qvm_ls.main(['--raw-list', '*minimal'], app=app) + self.assertEqual(stdout.getvalue(), + 'debian-13-minimal\nfedora-41-minimal\n') + + with qubesadmin.tests.tools.StdoutBuffer() as stdout: + qubesadmin.tools.qvm_ls.main(['--raw-list', '????'], app=app) + self.assertEqual(stdout.getvalue(), + 'dom0\n') + + with qubesadmin.tests.tools.StdoutBuffer() as stdout: + qubesadmin.tools.qvm_ls.main(['--raw-list', '??????-[rs]*'], app=app) + self.assertEqual(stdout.getvalue(), + 'debian-sid\nfedora-rawhide\n') + + with qubesadmin.tests.tools.StdoutBuffer() as stdout: + qubesadmin.tools.qvm_ls.main(['--raw-list', '??????-[!14s]*'], app=app) + self.assertEqual(stdout.getvalue(), + 'fedora-rawhide\n') + def test_110_network_tree(self): app = TestApp() app.domains = TestVMCollection( diff --git a/qubesadmin/tools/__init__.py b/qubesadmin/tools/__init__.py index 43f054d4..e86f48c3 100644 --- a/qubesadmin/tools/__init__.py +++ b/qubesadmin/tools/__init__.py @@ -24,6 +24,7 @@ from __future__ import print_function import argparse +import fnmatch import importlib import logging import os @@ -38,7 +39,6 @@ #: constant returned when some action should be performed on all qubes VM_ALL = object() - class QubesAction(argparse.Action): ''' Interface providing a convinience method to be called, after `namespace.app` is instantiated. @@ -151,6 +151,8 @@ def __call__(self, parser, namespace, values, option_string=None): setattr(namespace, self.dest, values) def parse_qubes_app(self, parser, namespace): + ''' Set ``namespace.domains`` to ``values`` ''' + # pylint: disable=too-many-nested-blocks assert hasattr(namespace, 'app') setattr(namespace, 'domains', []) app = namespace.app @@ -175,7 +177,16 @@ def parse_qubes_app(self, parser, namespace): except KeyError: parser.error('no such domain: {!r}'.format(vm_name)) else: - for vm_name in getattr(namespace, self.dest): + destinations = set() + for destination in getattr(namespace, self.dest): + if any(wildcard in destination for wildcard in '*?[!]'): + for domain in app.domains: + if fnmatch.fnmatch(domain.name, destination): + destinations.add(domain.name) + else: + destinations.add(destination) + + for vm_name in destinations: try: namespace.domains += [app.domains[vm_name]] except KeyError: