1 # -*- coding: utf-8 -*-
2 #---------------------------------------------------------------
3 # Project : Mandriva Linux
6 # Version : $Id: MenuCheck.py 1885 2011-09-13 18:15:29Z scop $
7 # Author : Frederic Lepied
8 # Created On : Mon Mar 20 07:43:37 2000
9 #---------------------------------------------------------------
16 from Filter import addDetails, printError, printInfo, printWarning
22 DEFAULT_VALID_SECTIONS = (
24 'Office/Address Books',
25 'Office/Communications/Fax',
26 'Office/Communications/PDA',
27 'Office/Communications/Phone',
28 'Office/Communications/Other',
31 'Office/Presentations',
33 'Office/Spreadsheets',
34 'Office/Tasks Management',
35 'Office/Time Management',
36 'Office/Wordprocessors',
39 'Internet/File Transfer',
40 'Internet/Instant Messaging',
43 'Internet/Remote Access',
44 'Internet/Video Conference',
45 'Internet/Web Browsers',
46 'Internet/Web Editors',
48 'Multimedia/Graphics',
52 'System/Archiving/Backup',
53 'System/Archiving/CD Burning',
54 'System/Archiving/Compression',
55 'System/Archiving/Other',
56 'System/Configuration/Boot and Init',
57 'System/Configuration/GNOME',
58 'System/Configuration/Hardware',
59 'System/Configuration/KDE',
60 'System/Configuration/Networking',
61 'System/Configuration/Packaging',
62 'System/Configuration/Printing',
63 'System/Configuration/Users',
64 'System/Configuration/Other',
67 'System/Session/Windowmanagers',
71 'More Applications/Accessibility',
72 'More Applications/Communications',
73 'More Applications/Databases',
74 'More Applications/Development/Code Generators',
75 'More Applications/Development/Development Environments',
76 'More Applications/Development/Interpreters',
77 'More Applications/Development/Tools',
78 'More Applications/Development/Other',
79 'More Applications/Documentation',
80 'More Applications/Editors',
81 'More Applications/Education/Economy',
82 'More Applications/Education/Geography',
83 'More Applications/Education/History',
84 'More Applications/Education/Languages',
85 'More Applications/Education/Literature',
86 'More Applications/Education/Sciences',
87 'More Applications/Education/Sports',
88 'More Applications/Education/Other',
89 'More Applications/Emulators',
90 'More Applications/Finances',
91 'More Applications/Games/Adventure',
92 'More Applications/Games/Arcade',
93 'More Applications/Games/Boards',
94 'More Applications/Games/Cards',
95 'More Applications/Games/Puzzles',
96 'More Applications/Games/Sports',
97 'More Applications/Games/Strategy',
98 'More Applications/Games/Toys',
99 'More Applications/Games/Other',
100 'More Applications/Sciences/Artificial Intelligence',
101 'More Applications/Sciences/Astronomy',
102 'More Applications/Sciences/Biology',
103 'More Applications/Sciences/Chemistry',
104 'More Applications/Sciences/Computer Science',
105 'More Applications/Sciences/Data visualization',
106 'More Applications/Sciences/Electricity',
107 'More Applications/Sciences/Geosciences',
108 'More Applications/Sciences/Image Processing',
109 'More Applications/Sciences/Mathematics',
110 'More Applications/Sciences/Numerical Analysis',
111 'More Applications/Sciences/Parallel Computing',
112 'More Applications/Sciences/Physics',
113 'More Applications/Sciences/Robotics',
114 'More Applications/Sciences/Other',
115 'More Applications/Other',
118 DEFAULT_EXTRA_MENU_NEEDS = (
125 DEFAULT_ICON_PATH = (('/usr/share/icons/', 'normal'),
126 ('/usr/share/icons/mini/', 'mini'),
127 ('/usr/share/icons/large/', 'large'))
129 DEFAULT_LAUNCHERS = (['(?:/usr/bin/)?kdesu', ('/usr/bin/kdesu', 'kdesu')],
130 ['(?:/usr/bin/)?launch_x11_clanapp', ('/usr/bin/launch_x11_clanapp', 'clanlib', 'libclanlib0')],
131 ['(?:/usr/bin/)?soundwrapper', None],
134 menu_file_regex = re.compile('^/usr/lib/menu/([^/]+)$')
135 old_menu_file_regex = re.compile('^/usr/share/(gnome/apps|applnk)/([^/]+)$')
136 package_regex = re.compile('\?package\((.*)\):')
137 needs_regex = re.compile('needs=(\"([^\"]+)\"|([^ \t\"]+))')
138 section_regex = re.compile('section=(\"([^\"]+)\"|([^ \t\"]+))')
139 title_regex = re.compile('[\"\s]title=(\"([^\"]+)\"|([^ \t\"]+))')
140 longtitle_regex = re.compile('longtitle=(\"([^\"]+)\"|([^ \t\"]+))')
141 command_regex = re.compile('command=(?:\"([^\"]+)\"|([^ \t\"]+))')
142 icon_regex = re.compile('icon=\"?([^\" ]+)')
143 valid_sections = Config.getOption('ValidMenuSections', DEFAULT_VALID_SECTIONS)
144 update_menus_regex = re.compile('^[^#]*update-menus', re.MULTILINE)
145 standard_needs = Config.getOption('ExtraMenuNeeds', DEFAULT_EXTRA_MENU_NEEDS)
146 icon_paths = Config.getOption('IconPath', DEFAULT_ICON_PATH)
147 xpm_ext_regex = re.compile('/usr/share/icons/(mini/|large/).*\.xpm$')
148 icon_ext_regex = re.compile(Config.getOption('IconFilename', '.*\.png$'))
149 version_regex = re.compile('([0-9.][0-9.]+)($|\s)')
150 launchers = Config.getOption('MenuLaunchers', DEFAULT_LAUNCHERS)
151 xdg_migrated_regex = re.compile('xdg=\"?([^\" ]+)')
155 l[0] = re.compile(l[0])
158 class MenuCheck(AbstractCheck.AbstractCheck):
161 AbstractCheck.AbstractCheck.__init__(self, 'MenuCheck')
163 def check(self, pkg):
164 # Check only binary package
171 for fname, pkgfile in files.items():
173 res = menu_file_regex.search(fname)
176 basename = res.group(1)
177 if not stat.S_ISREG(mode):
178 printError(pkg, 'non-file-in-menu-dir', fname)
180 if basename != pkg.name:
181 printWarning(pkg, 'non-coherent-menu-filename', fname)
182 if mode & 0444 != 0444:
183 printError(pkg, 'non-readable-menu-file', fname)
185 printError(pkg, 'executable-menu-file', fname)
188 # Check old menus from KDE and GNOME
189 res = old_menu_file_regex.search(fname)
191 if stat.S_ISREG(mode):
192 printError(pkg, 'old-menu-entry', fname)
194 # Check non transparent xpm files
195 res = xpm_ext_regex.search(fname)
197 if stat.S_ISREG(mode) and not pkg.grep('None",', fname):
198 printWarning(pkg, 'non-transparent-xpm', fname)
199 if fname.startswith('/usr/lib64/menu'):
200 printError(pkg, 'menu-in-wrong-dir', fname)
203 postin = pkg[rpm.RPMTAG_POSTIN] or \
204 pkg.scriptprog(rpm.RPMTAG_POSTINPROG)
206 printError(pkg, 'menu-without-postin')
207 elif not update_menus_regex.search(postin):
208 printError(pkg, 'postin-without-update-menus')
210 postun = pkg[rpm.RPMTAG_POSTUN] or \
211 pkg.scriptprog(rpm.RPMTAG_POSTUNPROG)
213 printError(pkg, 'menu-without-postun')
214 elif not update_menus_regex.search(postun):
215 printError(pkg, 'postun-without-update-menus')
217 directory = pkg.dirName()
219 # remove comments and handle cpp continuation lines
220 cmd = Pkg.getstatusoutput(('/lib/cpp', directory + f), True)[1]
222 for line in cmd.splitlines():
223 if not line.startswith('?'):
225 res = package_regex.search(line)
227 package = res.group(1)
228 if package != pkg.name:
230 'incoherent-package-value-in-menu',
233 printInfo(pkg, 'unable-to-parse-menu-entry', line)
236 res = command_regex.search(line)
238 command_line = (res.group(1) or res.group(2)).split()
239 command = command_line[0]
240 for launcher in launchers:
241 if not launcher[0].search(command):
245 if ('/bin/' + command_line[0] in files or
246 '/usr/bin/' + command_line[0] in files
247 or '/usr/X11R6/bin/' + command_line[0]
251 for l in launcher[1]:
252 if l in pkg.req_names():
257 'use-of-launcher-in-menu-but-no-requires-on',
259 command = command_line[1]
262 if command[0] == '/':
263 if command not in files:
264 printWarning(pkg, 'menu-command-not-in-package',
266 elif not ('/bin/' + command in files or
267 '/usr/bin/' + command in files or
268 '/usr/X11R6/bin/' + command in files):
269 printWarning(pkg, 'menu-command-not-in-package',
272 printWarning(pkg, 'missing-menu-command')
275 res = longtitle_regex.search(line)
278 title = grp[1] or grp[2]
279 if title[0] != title[0].upper():
280 printWarning(pkg, 'menu-longtitle-not-capitalized',
282 res = version_regex.search(title)
284 printWarning(pkg, 'version-in-menu-longtitle',
287 printError(pkg, 'no-longtitle-in-menu', f)
290 res = title_regex.search(line)
293 title = grp[1] or grp[2]
294 if title[0] != title[0].upper():
295 printWarning(pkg, 'menu-title-not-capitalized',
297 res = version_regex.search(title)
299 printWarning(pkg, 'version-in-menu-title', title)
301 printError(pkg, 'invalid-title', title)
303 printError(pkg, 'no-title-in-menu', f)
306 res = needs_regex.search(line)
309 needs = (grp[1] or grp[2]).lower()
310 if needs in ('x11', 'text' ,'wm'):
311 res = section_regex.search(line)
314 section = grp[1] or grp[2]
315 # don't warn entries for sections
316 if command and section not in valid_sections:
317 printError(pkg, 'invalid-menu-section',
320 printInfo(pkg, 'unable-to-parse-menu-section',
322 elif needs not in standard_needs:
323 printInfo(pkg, 'strange-needs', needs, f)
325 printInfo(pkg, 'unable-to-parse-menu-needs', line)
327 res = icon_regex.search(line)
330 if not icon_ext_regex.search(icon):
331 printWarning(pkg, 'invalid-menu-icon-type', icon)
332 if icon[0] == '/' and needs == 'x11':
333 printWarning(pkg, 'hardcoded-path-in-menu-icon',
336 for path in icon_paths:
337 if (path[0] + icon) not in files:
339 path[1] + '-icon-not-in-package',
342 printWarning(pkg, 'no-icon-in-menu', title)
344 res = xdg_migrated_regex.search(line)
346 if not res.group(1).lower() == "true":
347 printError(pkg, 'non-xdg-migrated-menu')
349 printError(pkg, 'non-xdg-migrated-menu')
352 # Create an object to enable the auto registration of the test
356 'non-file-in-menu-dir',
357 '''/usr/lib/menu must not contain anything else than normal files.''',
359 'non-coherent-menu-filename',
360 '''The menu file name should be /usr/lib/menu/<package>.''',
362 'non-readable-menu-file',
363 '''The menu file isn't readable. Check the permissions.''',
369 'non-transparent-xpm',
370 '''xpm icon should be transparent for use in menus.''',
372 'menu-without-postin',
373 '''A menu file exists in the package but no %post scriptlet is present to call
376 'postin-without-update-menus',
377 '''A menu file exists in the package but its %post scriptlet doesn't call
380 'menu-without-postun',
381 '''A menu file exists in the package but no %postun scriptlet is present to call
384 'postun-without-update-menus',
385 '''A menu file exists in the package but its %postun scriptlet doesn't call
388 'incoherent-package-value-in-menu',
389 '''The package field of the menu entry isn't the same as the package name.''',
391 'use-of-launcher-in-menu-but-no-requires-on',
392 '''The menu command uses a launcher but there is no dependency in the package
393 that contains it.''',
395 'menu-command-not-in-package',
396 '''The command used in the menu isn't included in the package.''',
398 'menu-longtitle-not-capitalized',
399 '''The longtitle field of the menu doesn't start with a capital letter.''',
401 'version-in-menu-longtitle',
402 '''The longtitle filed of the menu entry contains a version. This is bad
403 because it will be prone to error when the version of the package changes.''',
405 'no-longtitle-in-menu',
406 '''The longtitle field isn't present in the menu entry.''',
408 'menu-title-not-capitalized',
409 '''The title field of the menu entry doesn't start with a capital letter.''',
411 'version-in-menu-title',
412 '''The title filed of the menu entry contains a version. This is bad
413 because it will be prone to error when the version of the package changes.''',
416 '''The title field isn't present in the menu entry.''',
418 'invalid-menu-section',
419 '''The section field of the menu entry isn't standard.''',
421 'unable-to-parse-menu-section',
422 '''rpmlint wasn't able to parse the menu section. Please report.''',
424 'hardcoded-path-in-menu-icon',
425 '''The path of the icon is hardcoded in the menu entry. This prevent multiple
426 sizes of the icon from being found.''',
428 'normal-icon-not-in-package',
429 '''The normal icon isn't present in the package.''',
431 'mini-icon-not-in-package',
432 '''The mini icon isn't present in the package.''',
434 'large-icon-not-in-package',
435 '''The large icon isn't present in the package.''',
438 '''The menu entry doesn't contain an icon field.''',
441 '''The menu title contains invalid characters like /.''',
443 'missing-menu-command',
444 '''The menu file doesn't contain a command.''',
446 'menu-in-wrong-directory',
447 '''The menu files must be under /usr/lib/menu.''',
449 'non-xdg-migrated-menu',
450 '''The menu file has not been migrated to new XDG menu system.''',
454 # MenuCheck.py ends here
457 # indent-tabs-mode: nil
458 # py-indent-offset: 4