refactored MenuXDGCheck (rpm-software-management#225)

This commit is contained in:
Markéta Calábková 2020-02-13 10:30:03 +01:00 committed by Tomáš Chvátal
parent eb352739e5
commit 0b3add2728
1 changed files with 49 additions and 34 deletions

View File

@ -11,12 +11,14 @@ from pathlib import Path
import subprocess
from rpmlint.checks.AbstractCheck import AbstractFilesCheck
from rpmlint.pkg import is_utf8
STANDARD_BIN_DIRS = ('/bin', '/sbin', '/usr/bin', '/usr/sbin')
class MenuXDGCheck(AbstractFilesCheck):
"""
Check whether MenuXDG files installed by a package are valid.
"""
def __init__(self, config, output):
# desktop file need to be in $XDG_DATA_DIRS
# $ echo $XDG_DATA_DIRS/applications
@ -24,44 +26,19 @@ class MenuXDGCheck(AbstractFilesCheck):
super().__init__(config, output, r'(?:/usr|/etc/opt|/opt/.*)/share/applications/.*\.desktop$')
def parse_desktop_file(self, pkg, root, f, filename):
"""
Check the structure of a desktop file.
"""
cfp = cfgparser.RawConfigParser()
try:
with codecs.open(f, encoding='utf-8') as inputf:
cfp.read_file(inputf, filename)
except cfgparser.DuplicateSectionError as e:
self.output.add_info('E',
pkg, 'desktopfile-duplicate-section', filename,
'[%s]' % e.section)
except cfgparser.MissingSectionHeaderError:
self.output.add_info('E', pkg, 'desktopfile-missing-header', filename)
except cfgparser.Error as e:
# Only in Python >= 3.2
if (hasattr(cfgparser, 'DuplicateOptionError') and
isinstance(e, cfgparser.DuplicateOptionError)):
self.output.add_info('E', pkg, 'desktopfile-duplicate-option', filename,
'[%s]/%s' % (e.section, e.option))
else:
self.output.add_info('W', pkg, 'invalid-desktopfile', filename,
e.message.partition(':')[0])
self._handle_parser_error(pkg, filename, e)
except UnicodeDecodeError as e:
self.output.add_info('W', pkg, 'invalid-desktopfile', filename, 'Unicode error: %s' % (e))
self.output.add_info('E', pkg, 'non-utf8-desktopfile', filename, f'Unicode error: {e}')
else:
binary = None
if cfp.has_option('Desktop Entry', 'Exec'):
binary = cfp.get('Desktop Entry', 'Exec').partition(' ')[0]
if binary:
found = False
if binary.startswith('/'):
found = Path(root + binary).exists()
else:
for i in STANDARD_BIN_DIRS:
if Path(root + i + '/' + binary).exists():
# no need to check if the binary is +x, rpmlint does it
# in another place
found = True
break
if not found:
self.output.add_info('W', pkg, 'desktopfile-without-binary', filename, binary)
self._has_binary(pkg, root, cfp, filename)
def check_file(self, pkg, filename):
root = pkg.dirName()
@ -77,7 +54,45 @@ class MenuXDGCheck(AbstractFilesCheck):
error_printed = True
if not error_printed:
self.output.add_info('E', pkg, 'invalid-desktopfile', filename)
if not is_utf8(f):
self.output.add_info('E', pkg, 'non-utf8-desktopfile', filename)
self.parse_desktop_file(pkg, root, f, filename)
def _handle_parser_error(self, pkg, filename, e):
"""
Determine what to do with a caught configparser error.
"""
# I would love to use switch, however, each warning is printed differently
if (isinstance(e, cfgparser.MissingSectionHeaderError)):
self.output.add_info('E', pkg, 'desktopfile-missing-header', filename)
elif (isinstance(e, cfgparser.DuplicateSectionError)):
self.output.add_info('E', pkg, 'desktopfile-duplicate-section', filename,
'[{e.section}]')
elif (isinstance(e, cfgparser.DuplicateOptionError)):
self.output.add_info('E', pkg, 'desktopfile-duplicate-option', filename,
'[{e.section}]/{e.option}')
else:
self.output.add_info('E', pkg, 'invalid-desktopfile', filename,
e.message.partition(':')[0])
def _has_binary(self, pkg, root, cfp, filename):
"""
Check whether there is a binarry assigned to the desktop file.
Needs configparser instance, it is assumed to be called in parse_desktop_file.
"""
binary = None
if cfp.has_option('Desktop Entry', 'Exec'):
binary = cfp.get('Desktop Entry', 'Exec').partition(' ')[0]
# If there is no binary mentioned it is OK
if not binary:
return
if binary.startswith('/'):
if (Path(root + binary).exists()):
return
else:
for i in STANDARD_BIN_DIRS:
if Path(root + i + '/' + binary).exists():
# no need to check if the binary is +x, rpmlint does it
# in another place
return
self.output.add_info('W', pkg, 'desktopfile-without-binary', filename, binary)