summaryrefslogtreecommitdiffstats
path: root/pym/portage/util/_desktop_entry.py
blob: aa730ded323d65b9378b29d19fdd3a94ce4c3315 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# Copyright 2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

import io
import re
import subprocess
import sys

try:
	from configparser import Error as ConfigParserError, RawConfigParser
except ImportError:
	from ConfigParser import Error as ConfigParserError, RawConfigParser

from portage import _encodings, _unicode_encode, _unicode_decode
from portage.util import writemsg

def parse_desktop_entry(path):
	"""
	Parse the given file with RawConfigParser and return the
	result. This may raise an IOError from io.open(), or a
	ParsingError from RawConfigParser.
	"""
	parser = RawConfigParser()

	# use read_file/readfp in order to control decoding of unicode
	try:
		# Python >=3.2
		read_file = parser.read_file
	except AttributeError:
		read_file = parser.readfp

	with io.open(_unicode_encode(path,
		encoding=_encodings['fs'], errors='strict'),
		mode='r', encoding=_encodings['repo.content'],
		errors='replace') as f:
		content = f.read()

	# In Python 3.2, read_file does not support bytes in file names
	# (see bug #429544), so use StringIO to hide the file name.
	read_file(io.StringIO(content))

	return parser

_trivial_warnings = re.compile(r' looks redundant with value ')
_ignore_kde_key_re = re.compile(r'^\s*(configurationType\s*=|Type\s*=\s*Service)')
_ignore_kde_types = frozenset(
	["AkonadiAgent", "AkonadiResource", "Service", "ServiceType", "XSession"])

# kdebase-data installs files with [Currency Code] sections
# in /usr/share/locale/currency
# kdepim-runtime installs files with [Plugin] and [Wizard]
# sections in /usr/share/apps/akonadi/{plugins,accountwizard}
# kdm installs files with [KCM Locale], [KDE Desktop Pattern],
# [KdmGreeterTheme] and [Wallpaper] sections in various directories
# libkdegames installs files with [KDE Backdeck] sections in
# /usr/share/apps/carddecks/
# Various KDE games install files with [KGameTheme] sections
_ignore_kde_sections = ("Currency Code", "KCM Locale", "KDE Backdeck", "KDE Desktop Pattern", "KDE Desktop Program", "KdmGreeterTheme", "KGameTheme", "Plugin", "Wallpaper", "Wizard")

_ignored_errors = (
		# Ignore error for emacs.desktop:
		# https://bugs.freedesktop.org/show_bug.cgi?id=35844#c6
		'error: (will be fatal in the future): value "TextEditor" in key "Categories" in group "Desktop Entry" requires another category to be present among the following categories: Utility',
)

def validate_desktop_entry(path):
	args = ["desktop-file-validate", path]
	if sys.hexversion < 0x3000000 or sys.hexversion >= 0x3020000:
		# Python 3.1 does not support bytes in Popen args.
		args = [_unicode_encode(x, errors='strict') for x in args]
	proc = subprocess.Popen(args,
		stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
	output_lines = _unicode_decode(proc.communicate()[0]).splitlines()
	proc.wait()

	if output_lines:
		# Ignore kde extensions for bug #414125 and bug #432862.
		try:
			desktop_entry = parse_desktop_entry(path)
		except ConfigParserError:
			with io.open(_unicode_encode(path,
				encoding=_encodings['fs'], errors='strict'),
				mode='r', encoding=_encodings['repo.content'],
				errors='replace') as f:
				for line in f:
					if _ignore_kde_key_re.match(line):
						# Ignore kde extensions for bug #432862.
						del output_lines[:]
						break
		else:
			if desktop_entry.has_section("Desktop Entry"):
				try:
					entry_type = desktop_entry.get("Desktop Entry", "Type")
				except ConfigParserError:
					pass
				else:
					if entry_type in _ignore_kde_types:
						del output_lines[:]
				try:
					desktop_entry.get("Desktop Entry", "Hidden")
				except ConfigParserError:
					pass
				else:
					# The "Hidden" key appears to be unique to special kde
					# service files (which don't validate well), installed
					# in /usr/share/kde4/services/ by packages like
					# nepomuk-core and kurifilter-plugins.
					del output_lines[:]
			for section in _ignore_kde_sections:
				if desktop_entry.has_section(section):
					del output_lines[:]

	if output_lines:
		filtered_output = []
		for line in output_lines:
				if line[len(path)+2:] in _ignored_errors:
					continue
				filtered_output.append(line)
		output_lines = filtered_output

	if output_lines:
		output_lines = [line for line in output_lines
			if _trivial_warnings.search(line) is None]

	return output_lines

if __name__ == "__main__":
	for arg in sys.argv[1:]:
		for line in validate_desktop_entry(arg):
			writemsg(line + "\n", noiselevel=-1)