119 lines
4.2 KiB
Python
119 lines
4.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
# check xdg file format violation
|
|
#
|
|
# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
|
|
#
|
|
|
|
import codecs
|
|
import os
|
|
try:
|
|
import ConfigParser as cfgparser
|
|
except ImportError:
|
|
import configparser as cfgparser
|
|
|
|
import AbstractCheck
|
|
from Filter import addDetails, printError, printWarning
|
|
from Pkg import getstatusoutput, is_utf8
|
|
|
|
STANDARD_BIN_DIRS = ('/bin', '/sbin', '/usr/bin', '/usr/sbin')
|
|
|
|
|
|
class MenuXDGCheck(AbstractCheck.AbstractFilesCheck):
|
|
def __init__(self):
|
|
# desktop file need to be in $XDG_DATA_DIRS
|
|
# $ echo $XDG_DATA_DIRS/applications
|
|
# /var/lib/menu-xdg:/usr/share
|
|
AbstractCheck.AbstractFilesCheck.__init__(
|
|
self, "MenuXDGCheck", r'(?:/usr|/etc/opt|/opt/.*)/share/applications/.*\.desktop$')
|
|
|
|
def parse_desktop_file(self, pkg, root, f, filename):
|
|
cfp = cfgparser.RawConfigParser()
|
|
try:
|
|
with codecs.open(f, encoding='utf-8') as inputf:
|
|
cfp.readfp(inputf, filename)
|
|
except cfgparser.DuplicateSectionError as e:
|
|
printError(
|
|
pkg, 'desktopfile-duplicate-section', filename,
|
|
'[%s]' % e.section)
|
|
except cfgparser.MissingSectionHeaderError:
|
|
printError(
|
|
pkg, 'desktopfile-missing-header', filename)
|
|
except cfgparser.Error as e:
|
|
# Only in Python >= 3.2
|
|
if (hasattr(cfgparser, 'DuplicateOptionError') and
|
|
isinstance(e, cfgparser.DuplicateOptionError)):
|
|
printError(
|
|
pkg, 'desktopfile-duplicate-option', filename,
|
|
'[%s]/%s' % (e.section, e.option))
|
|
else:
|
|
printWarning(
|
|
pkg, 'invalid-desktopfile', filename,
|
|
e.message.partition(':')[0])
|
|
except UnicodeDecodeError as e:
|
|
printWarning(
|
|
pkg, 'invalid-desktopfile', filename, 'Unicode error: %s' % (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 = os.path.exists(root + binary)
|
|
else:
|
|
for i in STANDARD_BIN_DIRS:
|
|
if os.path.exists(root + i + '/' + binary):
|
|
# no need to check if the binary is +x, rpmlint does it
|
|
# in another place
|
|
found = True
|
|
break
|
|
if not found:
|
|
printWarning(
|
|
pkg, 'desktopfile-without-binary', filename, binary)
|
|
|
|
def check_file(self, pkg, filename):
|
|
root = pkg.dirName()
|
|
f = root + filename
|
|
st = getstatusoutput(('desktop-file-validate', f), True)
|
|
if st[0]:
|
|
error_printed = False
|
|
for line in st[1].splitlines():
|
|
if 'error: ' in line:
|
|
printError(pkg, 'invalid-desktopfile', filename,
|
|
line.split('error: ')[1])
|
|
error_printed = True
|
|
if not error_printed:
|
|
printError(pkg, 'invalid-desktopfile', filename)
|
|
if not is_utf8(f):
|
|
printError(pkg, 'non-utf8-desktopfile', filename)
|
|
|
|
self.parse_desktop_file(pkg, root, f, filename)
|
|
|
|
|
|
check = MenuXDGCheck()
|
|
|
|
addDetails(
|
|
'invalid-desktopfile',
|
|
'''.desktop file is not valid, check with desktop-file-validate''',
|
|
|
|
'non-utf8-desktopfile',
|
|
'''.desktop file is not encoded in UTF-8''',
|
|
|
|
'desktopfile-without-binary',
|
|
'''the .desktop file is for a file not present in the package. You
|
|
should check the requires or see if this is not a error''',
|
|
|
|
'desktopfile-duplicate-section',
|
|
'''The .desktop file contains the mentioned section name twice, which
|
|
can trigger parsing ambiguities. Remove the duplicate.''',
|
|
|
|
'desktopfile-duplicate-option',
|
|
'''The .desktop file contains the mentioned option key twice,
|
|
which can trigger parsing ambiguities. Remove the duplicate.''',
|
|
|
|
'desktopfile-missing-header',
|
|
'''The .desktop file should start with a section header.''',
|
|
)
|