Skip to content

Commit 8dc8be7

Browse files
committed
fix menu file leftover on vm remove
1 parent 75c9924 commit 8dc8be7

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

qubesappmenus/__init__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,11 +501,36 @@ def appmenus_remove(self, vm, refresh_cache=True):
501501
refresh_cache)
502502
shutil.rmtree(appmenus_dir)
503503

504+
self._remove_menu_files(vm)
505+
504506
if refresh_cache:
505507
if 'KDE_SESSION_UID' in os.environ:
506508
subprocess.call(['kbuildsycoca' +
507509
os.environ.get('KDE_SESSION_VERSION', '4')])
508510

511+
@staticmethod
512+
def _remove_menu_files(vm):
513+
"""Remove .menu files for a VM from ~/.config/menus/applications-merged/
514+
515+
xdg-desktop-menu uninstall does not always clean these up (errors
516+
are suppressed, partial installs can leave entries behind).
517+
"""
518+
menus_dir = os.path.join(xdg.BaseDirectory.xdg_config_home,
519+
'menus', 'applications-merged')
520+
if not os.path.isdir(menus_dir):
521+
return
522+
vm_name = str(vm)
523+
escaped = vm_name_escape(vm_name)
524+
for prefix in ('qubes-vm-directory', 'qubes-dispvm-directory'):
525+
with contextlib.suppress(FileNotFoundError):
526+
os.unlink(os.path.join(menus_dir,
527+
'user-' + prefix + escaped + '.menu'))
528+
# also try old format (before VM name escaping was introduced)
529+
with contextlib.suppress(FileNotFoundError):
530+
os.unlink(os.path.join(menus_dir,
531+
'user-' + prefix + '-' +
532+
vm_name + '.menu'))
533+
509534
def appicons_create(self, vm, srcdirs=(), force=False):
510535
"""Create/update applications icons"""
511536
if not srcdirs:

qubesappmenus/tests.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import io
2626
import os
27+
import shutil
2728
import tempfile
2829
import sys
2930

@@ -744,6 +745,64 @@ def test_132_get_available_does_not_require_unstable_flag(
744745
self.assertEqual(stdout.getvalue(), 'xterm.desktop - XTerm\n')
745746

746747

748+
@unittest.mock.patch('subprocess.check_call')
749+
def test_140_remove_cleans_menu_files(self, mock_subprocess):
750+
tpl = TestVM('test-inst-tpl',
751+
klass='TemplateVM',
752+
virt_mode='pvh',
753+
updateable=True,
754+
provides_network=False,
755+
label=self.app.labels[1])
756+
self.ext.appmenus_init(tpl)
757+
appvm = TestVM('test-inst-app',
758+
klass='AppVM',
759+
template=tpl,
760+
virt_mode='pvh',
761+
updateable=False,
762+
provides_network=False,
763+
label=self.app.labels[1])
764+
self.ext.appmenus_init(appvm)
765+
self.ext.appmenus_create(appvm, refresh_cache=False)
766+
767+
config_dir = tempfile.mkdtemp()
768+
try:
769+
menus_dir = os.path.join(config_dir, 'menus', 'applications-merged')
770+
os.makedirs(menus_dir)
771+
escaped = qubesappmenus.vm_name_escape(appvm.name)
772+
# current-format .menu file
773+
menu_file = os.path.join(menus_dir,
774+
'user-qubes-vm-directory' + escaped + '.menu')
775+
# old-format .menu file (pre-escaping)
776+
old_menu_file = os.path.join(menus_dir,
777+
'user-qubes-vm-directory-' + appvm.name + '.menu')
778+
for path in (menu_file, old_menu_file):
779+
with open(path, 'w', encoding='utf-8') as f:
780+
f.write('<Menu/>\n')
781+
782+
with unittest.mock.patch('xdg.BaseDirectory.xdg_config_home',
783+
config_dir):
784+
self.ext.appmenus_remove(appvm, refresh_cache=False)
785+
786+
self.assertPathNotExists(menu_file)
787+
self.assertPathNotExists(old_menu_file)
788+
finally:
789+
shutil.rmtree(config_dir)
790+
791+
def test_141_remove_menu_files_missing_dir(self):
792+
config_dir = tempfile.mkdtemp()
793+
try:
794+
menus_dir = os.path.join(config_dir, 'menus', 'applications-merged')
795+
with unittest.mock.patch('xdg.BaseDirectory.xdg_config_home',
796+
config_dir), \
797+
unittest.mock.patch('os.unlink') as mock_unlink:
798+
# Missing applications-merged directory should be ignored.
799+
qubesappmenus.Appmenus._remove_menu_files('test-vm')
800+
mock_unlink.assert_not_called()
801+
self.assertFalse(os.path.exists(menus_dir))
802+
finally:
803+
shutil.rmtree(config_dir)
804+
805+
747806
def list_tests():
748807
return (TC_00_Appmenus,)
749808

0 commit comments

Comments
 (0)