[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#433411: marked as done (lintian: New checks for FreeDesktop's desktop files)



Your message dated Sun, 05 Aug 2007 19:32:03 +0000
with message-id <E1IHlpb-00079I-55@ries.debian.org>
and subject line Bug#433411: fixed in lintian 1.23.33
has caused the attached Bug report to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what I am
talking about this indicates a serious mail system misconfiguration
somewhere.  Please contact me immediately.)

Debian bug tracking system administrator
(administrator, Debian Bugs database)

--- Begin Message ---
Package: lintian 
Version: 1.23.32
Priority: wishlist
Tags: patch

Following the recent discussion at debian-devel related to .desktop files
I've noticed that we lack some lintian checks for common issues in desktop
files (mispelled categories, wrong key value pairs, etc...)

Even though we don't have a policy for Desktop files, since most Desktop
environments (KDE, GNOME) are using them it might be sane to have a check for
desktop files just like we have for menu files.

I've written a first attempt at such check, heavily based on the current
menu-format method and reusing some of its code. It is capable of detecting
wrong Categories and invalid Type values and should be useful to detect
.desktop files which need to be fixed. 

Notice that it could be improved to do much more tests, I'm not sure I'll
handle them myself but maybe this will help others scratch their itch..

Please consider its inclusion into the lintian lab.

Thanks,

Javier
# desktop format -- lintian check script -*- perl -*-

# Copyright (C) 2007 by Javier Fernandez-Sanguino
# based on the menu lintian check written by 
# Copyright (C) 1998 by Joey Hess
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, you can find it on the World Wide
# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.
# 
# 
# This lintian check aims at implement some standard check for Desktop files
# which are currently not covered by Debian Policy (only menu entries are)
#
# This is a barebones module, it should be extended to check for some more things
# from FreeDesktop's standard:
#
# - Look for Deprecated Items
# - Check field codes in the Exec key
# - Check fields with locales
# - Check Group headers
# - ....
#

package Lintian::desktop_format;
use strict;
use Tags;
use Util;
use File::Basename;

# Authorative source of desktop keys:
# http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html
#
# This is a list of all keys that should be in every desktop entry.
my @req_keys=qw(Type Name);

# This is a list of all known keys.
my @known_keys=qw(
        Type
        Name
        Version
        GenericName
        NoDisplay
        Comment
        Icon
        Hidden
        OnlyShowIn
        NotShowIn
        TryExec
        Exec
        Path
        Terminal
        MimeType
        Categories
        StartupNotify
        StartupWMClass
        URL
);
my @deprecated_keys=qw(
        Encoding
        MiniIcon
        TerminalOptions
        Protocols
        Extensions
        BinaryPattern
        MapNotify
        SwallowTitle
        SwallowExec
        SortOrder
        FilePattern
);

# Authorative source of desktop categories
# http://standards.freedesktop.org/menu-spec/menu-spec-1.0.html#category-registry

# This is a list of all valid section on the root menu.
my @root_categories=qw(AudioVideo Audio Video Development Education Game Graphics Network Office Settings System Utility);

# This is a list of all additional categories
my @categories=qw(
        Building
        Debugger
        IDE
        GUIDesigner
        Profiling
        RevisionControl
        Translation
        Calendar
        ContactManagement
        Database
        Dictionary
        Chart
        Email
        Finance
        FlowChart
        PDA
        ProjectManagement
        Presentation
        Spreadsheet
        WordProcessor
        2DGraphics
        VectorGraphics
        RasterGraphics
        3DGraphics
        Scanning
        OCR
        Photography
        Publishing
        Viewer
        TextTools
        DesktopSettings
        HardwareSettings
        Printing
        PackageManager
        Dialup
        InstantMessaging
        Chat
        IRCClient
        FileTransfer
        HamRadio
        News
        P2P
        RemoteAccess
        Telephony
        TelephonyTools
        VideoConference
        WebBrowser
        WebDevelopment
        Midi
        Mixer
        Sequencer
        Tuner
        TV
        AudioVideoEditing
        Player
        Recorder
        DiscBurning
        ActionGame
        AdventureGame
        ArcadeGame
        BoardGame
        BlocksGame
        CardGame
        KidsGame
        LogicGame
        RolePlaying
        Simulation
        SportsGame
        StrategyGame
        Art
        Construction
        Music
        Languages
        Science
        ArtificialIntelligence
        Astronomy
        Biology
        Chemistry
        ComputerScience
        DataVisualization
        Economy
        Electricity
        Geography
        Geology
        Geoscience
        History
        ImageProcessing
        Literature
        Math
        NumericalAnalysis
        MedicalSoftware
        Physics
        Robotics
        Sports
        ParallelComputing
        Amusement
        Archiving
        Compression
        Electronics
        Emulator
        Engineering
        FileTools
        FileManager
        TerminalEmulator
        Filesystem
        Monitor
        Security
        Accessibility
        Calculator
        Clock
        TextEditor
        Documentation
        Core
        KDE
        GNOME
        GTK
        Qt
        Motif
        Java
        ConsoleOnly
);

# Path in which to search for binaries referenced in menu entries.
my @path = qw(/usr/local/bin/ /usr/bin/ /bin/ /usr/X11R6/bin/ /usr/games/);

my %known_keys_hash;
my %deprecated_keys_hash;
my %root_categories_hash;
my %categories_hash;

my %all_files = ();
my %all_links = ();

# -----------------------------------

sub run {

    my $pkg = shift;
    my $type = shift;

# Things worth hashing.
    foreach my $tag (@known_keys) {
        $known_keys_hash{$tag}=1;
    }
    foreach my $tag (@deprecated_keys) {
        $deprecated_keys_hash{$tag}=1;
    }
    foreach my $section (@root_categories) {
        $root_categories_hash{$section}=1;
    }
    foreach my $section (@categories) {
        $categories_hash{$section}=1;
    }

# read package contents
    open(IN,"index") or fail("cannot open index file index: $!");
    while (<IN>) {
        chomp;
        my ($perm,$owner,$size,$date,$time,$file) = split(' ', $_, 6);
        $file =~ s,^(\./),,;
        add_file_link_info ($file);
        $file =~ s/ link to .*//;
        $file =~ s/ -> .*//;
        my $operm = perm2oct($perm);

        if ($perm =~ m,^-,o) { # file checks
# desktop file?
            if ($file =~ m/\.desktop$/o) { # correct permissions?
                if ($perm =~ m,x,o) { 
                    tag "executable-desktop-file", sprintf("$file %04o",$operm);
                }
                # TODO: This should provide the 
                VerifyFile($file, $file);
            }
        }
    }
    close IN;

}

# -----------------------------------

# Pass this a line of a menu file, it sanitizes it and
# verifies that it is correct.
sub VerifyFile {
    my ( $desktopfile, $fullname ) = @_;

    my %vals;

    open (DESKTOP, "unpacked/$fullname") or fail("cannot open desktop file $fullname: $!");
    my $linecount = 0;
    while ( my $line = <DESKTOP> ) {
        chomp $line; 
        $linecount++;
        next if ( $line =~ m/^\s*\#/ or $line = ~ m/^\s*$/);

# Tag = Value
# TODO: We do not check for properly formatted localised values for keys
# but might be worth checking if they are properly formatted (not their value)
        if ( $line =~ /^(.*?)\s*=\s*(.*?)$/ ) {
            my $tag = $1;
            my $value = $2;

            if (exists $vals{$tag}) {
                tag "duplicated-key-in-desktop-entry", "$fullname $1:$linecount";
            }

            $vals{$tag} = $value;
        }
    }
    close DESKTOP;

# Now validate the data in the desktop file.

# Test for important keys.
    foreach my $tag (@req_keys) {
        unless ( exists($vals{$tag}) && defined($vals{$tag}) ) {
            tag "desktop-entry-missing-required-key", "$tag $fullname:$linecount";
        }
    }
# Make sure all keys are known and no deprecated keys are being used
    foreach my $tag (keys %vals) {
        if ( $deprecated_keys_hash{$tag} ) {
            tag "desktop-entry-contains-deprecated-key", "$tag $fullname:$linecount";
        } elsif (! $known_keys_hash{$tag} && $tag !~ /^X-/ ) {
        # TODO: Will produce false positives for keys reserved by KDE
        # which do not use X-KDE (see Standard)
            tag "desktop-entry-contains-unknown-key", "$tag $fullname:$linecount";
        }
    }


# TODO: Check for deprecated keys: Encoding, MiniIcon, TerminalOptions, Protocols, 
#       Extensions, BinaryPattern, MapNotify, SwallowTitle, SwallowExec, SortOrder
#       FilePattern,

    if (exists($vals{'Exec'})) {
	VerifyExec( $fullname, $linecount, $vals{'Exec'});
    }

    if (exists($vals{'Icon'})) {
	VerifyIcon( $fullname, $linecount, $vals{'Icon'}, 32);
    }

# Check the category tag
    if (exists($vals{'Categories'})) {
        # Is the main category there?
        my $ccats = 0; 
        foreach my $cat (keys %root_categories_hash) {
            $ccats++ if  $vals{'Categories'} =~ /$cat;?/;
        }
        if ( $ccats == 0 )  {
		tag "desktop-entry-lacks-main-category", "$fullname:$linecount"; 
        } elsif ( $ccats > 1 )  {
		tag "desktop-entry-multiple-main-category", "$fullname:$linecount";
        }

        foreach my $cat (split(';',$vals{'Categories'})) {
	    if (not $categories_hash{$cat})  {
		tag "desktop-entry-invalid-category", "$cat $fullname:$linecount";
            }
        }
    }

# TODO:
# - Check if the values correspond to the allowed type for a given key (boolean,
#   integer...)

}

sub VerifyCmd {
# Verify if commands are installed with the package.
# TODO: Should check quoting and the check special field codes in Exec

    my ( $fullname, $linecount, $exec) = @_;

    # Read the file index:
    my %file_index;
    open(FILE_INDEX,"index") or fail("cannot open index file index: $!");
    while(<FILE_INDEX>) {
        $file_index{(split /\s+/, $_)[5]} = 1;
    }
    close FILE_INDEX;

# This routine handles su wrappers.  The option parsing here is ugly and dead-simple,
# but it's hopefully good enough for what will show up in desktop files.
# su-to-root and sux require -c options, kdesu optionally allows one, and
# gksu has the command at the end of its arguments.
    my @com = split(' ',$exec);
    my $cmd;
    if ($com[0] eq "/usr/sbin/su-to-root") {
	tag "su-to-root-with-usr-sbin", "$fullname:$linecount";
    } elsif ($com[0] =~ m,^(?:/usr/bin/)?(su-to-root|gksu|kdesu|sux)$,) {
	my $wrapper = $1;
	shift @com;
	while (@com) {
	    unless ($com[0]) {
		shift @com;
		next;
	    }
	    if ($com[0] eq '-c') {
		$cmd = $com[1];
		last;
	    } elsif ($com[0] =~ /^-[Dfmupi]|^--(user|description|message)/) {
		shift @com;
		shift @com;
	    } elsif ($com[0] =~ /^-/) {
		shift @com;
	    } else {
		last;
	    }
	}
	if (!$cmd && $wrapper =~ /^(gk|kde)su$/) {
	    $cmd = $com[0];
	} elsif (!$cmd) {
	    tag "su-wrapper-without--c", "$fullname:$linecount $wrapper";
	}
    } else {
	$cmd = $com[0];
    }
    tag "desktop-command-not-in-package", "$fullname:$linecount $cmd"
	if ($cmd
	    && !($file_index{".$cmd"} || grep {$file_index{".".$_.$cmd}} @path));
}

# TODO: Shouldn't this allow PNG files too?
sub VerifyIcon {
    my ( $fullname, $linecount, $icon, $size) = @_;
    local *IN;

    if ($icon eq 'none') {
	tag "desktop-entry-uses-icon-none", "$fullname:$linecount";
	return;
    }

    if (not ($icon =~ m/\.xpm$/i)) {
	tag "desktop-icon-not-in-xpm-format", "$icon";
	return;
    }

    # Try the explicit location, and if that fails, try the standard path.
    my $iconfile = "unpacked/$icon";
    if (! -f $iconfile) {
	$iconfile = "unpacked/usr/share/pixmaps/$icon";
    }

    if (! open IN, $iconfile) {
	tag "desktop-icon-missing", "$icon";
	return;
    }

    my $parse = "XPM header";
    my $line;
    do { defined ($line = <IN>) or goto parse_error; }
    until ($line =~ /\/\*\s*XPM\s*\*\//);

    $parse = "size line";
    do { defined ($line = <IN>) or goto parse_error; }
    until ($line =~ /"\s*([0-9]+)\s*([0-9]+)\s*([0-9]+)\s*([0-9]+)\s*"/);
    my $width = $1 + 0;
    my $height = $2 + 0;
    my $numcolours = $3 + 0;
    my $cpp = $4 + 0;
    
    if ($width > $size || $height > $size) {
	tag "desktop-icon-too-big", "$icon: ${width}x${height} > ${size}x${size}";
    }

    close IN or die;
    return;

parse_error:
    close IN or die;
    tag "desktop-icon-cannot-be-parsed", "$icon: looking for $parse";
    return;
}

1;

# -----------------------------------

# Add file and link to %all_files and %all_links.  Note that both files and
# links have to include a leading /.
sub add_file_link_info {
    my $file = shift;
    my $link = undef;

    $file = "/" . $file if (not $file =~ m%^/%); # make file absolute
    $file =~ s%/+%/%g;				 # remove duplicated `/'
    ($file, $link) = split(/ -> /, $file);

    $all_files{$file} = 1;

    if (defined $link) {
	if (not $link =~ m,^/,) {		  # not absolute link
	    $link = "/" . $link;		  # make sure link starts with '/'
	    $link =~ s,/+\./+,/,g;		  # remove all /./ parts
	    my $dcount = 1;
	    while ($link =~ s,^/+\.\./+,/,) {	  #\ count & remove
	       $dcount++;			  #/ any leading /../ parts
	    }
	    my $f = $file;
	    while ($dcount--) {			  #\ remove last $dcount
		$f =~ s,/[^/]*$,,;		  #/ path components from $file
	    }
	    $link = $f . $link;			  # now we should have absolute link
	}
	$all_links{$file} = $link unless ($link eq $file);
    }
}



1;

# vim: syntax=perl ts=8 sw=4
Check-Script: desktop-format
Author: Javier Fernandez-Sanguino Pen~a <jfs@debian.rog>
Abbrev: dkf
Standards-Version: 3.6.1
Type: binary
Unpack-Level: 1
Info: This script validates the format of desktop files.

Tag: unparsable-desktop-entry
Type: error
Info: An entry of the desktop file cannot be parsed as a series of key=value
 pairs. 

Tag: duplicated-key-in-desktop-entry
Type: warning
Info: The desktop entry contains two instances of the same key. This is just a
 waste of space, as only one will be used.

Tag: desktop-entry-missing-required-key
Type: error
Info: The desktop entry has a line that is missing a required key.
 See: http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html#recognized-keys

Tag: desktop-entry-contains-unknown-key
Type: warning
Info: The desktop entry has a line that has a key in it that is not one
 of the standard keys defined in the FreeDesktop specification and this
 key does not conform to the preferred method for introducing changes
 (via the 'X-' prefix). It's more likely the key's name is misspelled.
 See: http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html#recognized-keys

Tag: desktop-entry-contains-deprecated-key
Type: warning
Info: The desktop entry has a line that has a key in it that has been
 deprecated in the FreeDesktop specification.
 See: http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.0.html#deprecated-items

Tag: desktop-icon-not-in-xpm-format
Type: error
Info: Icons in the Debian desktop system should be in XPM format.
Ref: desktop manual 3.7

Tag: desktop-icon-missing
Type: warning
Info: This icon file couldn't be found.  If the path to the icon in the
 desktop file is an absolute path, make sure that icon exists at that path in
 the package.  If the path is relative or a simple filename, make sure the
 icon is installed in <tt>/usr/share/pixmaps</tt>, the default location.
 .
 If the icon is in a package this package depends on, add a lintian
 override for this warning.  lintian cannot check icons in other packages.
Ref: desktop manual 3.7

Tag: desktop-icon-too-big
Type: error
Info: Icons in the Debian desktop system should be at most 32x32 pixels
 (icon16x16 icons should of course be at most 16x16 pixels)
Ref: desktop manual 3.7

Tag: desktop-icon-cannot-be-parsed
Type: warning
Info: The icon file could not be parsed.  Perhaps this means a bad XPM file,
 or perhaps it means the lintian parsing needs to be improved.  If the
 window managers and standard tools accept the file then probably it's the
 latter; please file a bug on lintian then.

Tag: desktop-command-not-in-package
Type: warning
Info: The desktop entry specifies a command which is not available in the package.
 In most cases this is a typo or after you moved a binary around, but forgot
 to update the desktop file.

--- End Message ---
--- Begin Message ---
Source: lintian
Source-Version: 1.23.33

We believe that the bug you reported is fixed in the latest version of
lintian, which is due to be installed in the Debian FTP archive:

lintian_1.23.33.dsc
  to pool/main/l/lintian/lintian_1.23.33.dsc
lintian_1.23.33.tar.gz
  to pool/main/l/lintian/lintian_1.23.33.tar.gz
lintian_1.23.33_all.deb
  to pool/main/l/lintian/lintian_1.23.33_all.deb



A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to 433411@bugs.debian.org,
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Russ Allbery <rra@debian.org> (supplier of updated lintian package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing ftpmaster@debian.org)


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Format: 1.7
Date: Sun, 05 Aug 2007 11:59:15 -0700
Source: lintian
Binary: lintian
Architecture: source all
Version: 1.23.33
Distribution: unstable
Urgency: low
Maintainer: Debian Lintian Maintainers <lintian-maint@debian.org>
Changed-By: Russ Allbery <rra@debian.org>
Description: 
 lintian    - Debian package checker
Closes: 277441 431259 431395 431545 431629 431844 432268 432959 433411 433516 434744 434978 436058
Changes: 
 lintian (1.23.33) unstable; urgency=low
 .
   The "menu and cruft reorganization" release.
 .
   * checks/common_data.pm:
     + [CW] Add automaken as a known virtual package.
     + [CW] Update architectures to dpkg 1.14.5, adding solaris-* and lpia.
     + [RA] Add %known_obsolete_emacs.
   * checks/cruft{.desc,}:
     + [RA] Check for .git directories in source packages.  Thanks, Julien
       Cristau.  (Closes: #433516)
     + [RA] Substantially rewrite how all cruft checking against source
       packages is done, incorporating debdiff in the process.  There are
       now two tags for most source package cruft problems: one for files
       introduced in the Debian diff or in a native package, and one for
       files present upstream.  The former is at warning severity and the
       latter is at info severity, since it's usually not worth repackaging
       the upstream source to remove such files.  In the process,
       standardize the names of all of the tags and pull the regexes out
       into data instead of code for easier maintenance.  (Closes: #434744)
   * checks/debdiff{.desc}:
     + [RA] Removed, incorporated into checks/cruft.
   * checks/debian-readme:
     + [RA] Replace all uses of tag_error and tag_warn with just tag.
   * checks/fields{.desc,}:
     + [RA] Tag packages listing emacs21 as the preferred Emacs flavor in a
       dependency.  Thanks, Tatsuya Kinoshita.  (Closes: #434978)
     + [RA] Start tagging unversioned dependencies on coreutils again since
       the transition from fileutils is long-since finished.  Thanks,
       Guillem Jover.  (Closes: #436058)
   * checks/files{.desc,}:
     + [RA] Check for .git directories in binary packages.
   * checks/menu-format{.desc,}:
     + [RA] Switch to the new menu hierarchy, which will be in the next
       release of Policy.  Add specific checks for the major renamings to
       hopefully cut down on the confusion and provide some specific
       guidance.  Remove the code that allowed for applications to create
       new sub-menus, since the current menu documentation says not to do
       that.  (Closes: #431844)
     + [RA] Add checks of desktop files.  The checks so far are basic, but
       do include key and category verification.  Based heavily on work by
       Javier Fernández-Sanguino Peña.  (Closes: #277441, #433411)
   * checks/scripts{.desc,}:
     + [RA] If rm output is redirected to /dev/null, don't think that rm is
       removing /dev/null.  Thanks, Robert Luberda.  (Closes: #431259)
     + [RA] xjed also provides jed-script.  Thanks, Jörg Sommer.
       (Closes: #431629)
     + [RA] Don't complain about ruby libraries in /usr/lib/ruby that have
       shebang lines.  This is a common means for embedding unit tests in
       Ruby libraries.  Thanks, Paul van Tilburg.  (Closes: #431545)
     + [RA] Don't push depending directly on update-inetd in the long
       description of maintainer-script-needs-depends-on-update-inetd.
       Most packages should depend on inet-superserver.  Leave the check
       the same for the time being, however.
     + [RA] Replace all uses of tag_error and tag_warn with just tag.
   * checks/shared-libs:
     + [RA] Exclude udebs from dependency checking in the shlibs files
       since binary packages may legitimately declare udeb dependencies on
       other packages.  Thanks, Loïc Minier.  (Closes: #431395)
   * checks/spelling:
     + [RA] Replace all uses of tag_error and tag_warn with just tag.
   * checks/version-substvars:
     + [RA] Don't skip other checks for binNMUability when warning about
       the deprecated ${Source-Version} substvar.  Thanks, Lior Kaplan.
       (Closes: #432959)
 .
   * frontend/lintian:
     + [RA] Add \w+-backports to the known distribution list.  Thanks,
       Vincent Danjean.  (Closes: #432268)
 .
   * lib/Tags.pm:
     + [RA] Replace any newlines in the extra information to the tag
       function with \n.
 .
   * man/lintian.1:
     + [RA] Remove the mention of the debdiff check script.
Files: 
 8e2cba86358bff5966ca25742e17c624 803 devel optional lintian_1.23.33.dsc
 5b162f95452ff5f2b7101584a70f682f 345211 devel optional lintian_1.23.33.tar.gz
 303ef4f6699670f5a1208359ad6cebc9 292624 devel optional lintian_1.23.33_all.deb

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQFGtiKM+YXjQAr8dHYRAmDBAJ9qWZiVIIh/y1Tq3Vnb47hwrTMRwwCfWcVx
7mAbjW1OHk1PIqZG5giSqUw=
=J3wO
-----END PGP SIGNATURE-----


--- End Message ---

Reply to: