Skip to content

Commit 05b102f

Browse files
committed
fix menu file leftover on vm remove
1 parent 3667bff commit 05b102f

3 files changed

Lines changed: 85 additions & 1 deletion

File tree

.gitlab-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ checks:tests:
66
- pip3 install --quiet -r ci/requirements.txt
77
- git clone https://github.com/QubesOS/qubes-linux-utils ~/linux-utils
88
- git clone https://github.com/QubesOS/qubes-core-admin-client ~/core-admin-client
9-
- (cd ~/core-admin-client;python3 setup.py egg_info)
9+
- (cd ~/core-admin-client; if [ -f setup.py ]; then python3 setup.py egg_info; else python3 -m pip install --quiet --no-deps -e .; fi)
1010
script:
1111
- export PYTHONPATH=~/core-admin-client:~/linux-utils/imgconverter
1212
- python3 -m pylint qubesappmenus

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

@@ -727,6 +728,64 @@ def test_131_set_get_default_whitelist(self, mock_subprocess):
727728
self.assertEqual(whitelist, self.ext.get_default_whitelist(tpl))
728729

729730

731+
@unittest.mock.patch('subprocess.check_call')
732+
def test_140_remove_cleans_menu_files(self, mock_subprocess):
733+
tpl = TestVM('test-inst-tpl',
734+
klass='TemplateVM',
735+
virt_mode='pvh',
736+
updateable=True,
737+
provides_network=False,
738+
label=self.app.labels[1])
739+
self.ext.appmenus_init(tpl)
740+
appvm = TestVM('test-inst-app',
741+
klass='AppVM',
742+
template=tpl,
743+
virt_mode='pvh',
744+
updateable=False,
745+
provides_network=False,
746+
label=self.app.labels[1])
747+
self.ext.appmenus_init(appvm)
748+
self.ext.appmenus_create(appvm, refresh_cache=False)
749+
750+
config_dir = tempfile.mkdtemp()
751+
try:
752+
menus_dir = os.path.join(config_dir, 'menus', 'applications-merged')
753+
os.makedirs(menus_dir)
754+
escaped = qubesappmenus.vm_name_escape(appvm.name)
755+
# current-format .menu file
756+
menu_file = os.path.join(menus_dir,
757+
'user-qubes-vm-directory' + escaped + '.menu')
758+
# old-format .menu file (pre-escaping)
759+
old_menu_file = os.path.join(menus_dir,
760+
'user-qubes-vm-directory-' + appvm.name + '.menu')
761+
for path in (menu_file, old_menu_file):
762+
with open(path, 'w', encoding='utf-8') as f:
763+
f.write('<Menu/>\n')
764+
765+
with unittest.mock.patch('xdg.BaseDirectory.xdg_config_home',
766+
config_dir):
767+
self.ext.appmenus_remove(appvm, refresh_cache=False)
768+
769+
self.assertPathNotExists(menu_file)
770+
self.assertPathNotExists(old_menu_file)
771+
finally:
772+
shutil.rmtree(config_dir)
773+
774+
def test_141_remove_menu_files_missing_dir(self):
775+
config_dir = tempfile.mkdtemp()
776+
try:
777+
menus_dir = os.path.join(config_dir, 'menus', 'applications-merged')
778+
with unittest.mock.patch('xdg.BaseDirectory.xdg_config_home',
779+
config_dir), \
780+
unittest.mock.patch('os.unlink') as mock_unlink:
781+
# Missing applications-merged directory should be ignored.
782+
qubesappmenus.Appmenus._remove_menu_files('test-vm')
783+
mock_unlink.assert_not_called()
784+
self.assertFalse(os.path.exists(menus_dir))
785+
finally:
786+
shutil.rmtree(config_dir)
787+
788+
730789
def list_tests():
731790
return (TC_00_Appmenus,)
732791

0 commit comments

Comments
 (0)