cookutils rev 769

Add fix-desktop-file: check and fix errors, warnings and apply hints in .desktop files
author Aleksej Bobylev <al.bobylev@gmail.com>
date Sat Nov 07 16:00:41 2015 +0200 (2015-11-07)
parents 1e6ac34f05d7
children e177315d46eb
files Makefile cook fix-desktop-file
line diff
     1.1 --- a/Makefile	Sat Nov 07 02:30:09 2015 +0200
     1.2 +++ b/Makefile	Sat Nov 07 16:00:41 2015 +0200
     1.3 @@ -22,6 +22,7 @@
     1.4  	install -m 0755 -d $(DESTDIR)$(PREFIX)/share/cook/cooktest
     1.5  	install -m 0755 -d $(DESTDIR)$(PREFIX)/share/doc/cookutils
     1.6  	install -m 0755 cook $(DESTDIR)$(PREFIX)/bin
     1.7 +	install -m 0755 fix-desktop-file $(DESTDIR)$(PREFIX)/bin
     1.8  	install -m 0755 cooker $(DESTDIR)$(PREFIX)/bin
     1.9  	install -m 0755 cookiso $(DESTDIR)$(PREFIX)/bin
    1.10  	install -m 0755 cooklinux $(DESTDIR)$(PREFIX)/bin
    1.11 @@ -40,6 +41,7 @@
    1.12  uninstall-cook:
    1.13  	rm -rf \
    1.14  		$(DESTDIR)$(PREFIX)/bin/cook \
    1.15 +		$(DESTDIR)$(PREFIX)/bin/fix-desktop-file \
    1.16  		$(DESTDIR)$(PREFIX)/bin/cooker \
    1.17  		$(DESTDIR)$(PREFIX)/bin/cookiso \
    1.18  		$(DESTDIR)$(PREFIX)/bin/cooklinux \
     2.1 --- a/cook	Sat Nov 07 02:30:09 2015 +0200
     2.2 +++ b/cook	Sat Nov 07 16:00:41 2015 +0200
     2.3 @@ -473,6 +473,39 @@
     2.4  }
     2.5  
     2.6  
     2.7 +# Fix common errors and warnings in the .desktop files
     2.8 +
     2.9 +fix_desktop_files() {
    2.10 +	[ -d "$install/usr/share/applications" ] || return
    2.11 +
    2.12 +	if [ -n "$QA" -a -z "$(which desktop-file-validate)" ]; then
    2.13 +		_n 'Installing dep (web/cache): %s' 'desktop-file-utils-extra'
    2.14 +		tazpkg -gi desktop-file-utils-extra >/dev/null
    2.15 +		status
    2.16 +	fi
    2.17 +
    2.18 +	for desktop in $(find $install/usr/share/applications -name '*.desktop'); do
    2.19 +		# Sort out .desktop file (is prerequisite to correct working of `fix-desktop-file`)
    2.20 +		sdft "$desktop" -i
    2.21 +
    2.22 +		cp "$desktop" "$desktop.orig"
    2.23 +
    2.24 +		# Fix common errors in .desktop file
    2.25 +		fix-desktop-file "$desktop"
    2.26 +
    2.27 +		if [ -n "$QA" ]; then
    2.28 +			# Check the rest of errors, warnings and tips
    2.29 +			_ 'QA: Checking %s...' "$(basename $desktop)"
    2.30 +			diff "$desktop.orig" "$desktop"
    2.31 +			desktop-file-validate "$desktop"
    2.32 +			echo
    2.33 +		fi
    2.34 +
    2.35 +		rm "$desktop.orig"
    2.36 +	done
    2.37 +}
    2.38 +
    2.39 +
    2.40  # Find and strip: --strip-all (-s) or --strip-debug on static libs as well
    2.41  # as removing unneeded files like in Python packages. Cross compiled binaries
    2.42  # must be stripped with cross-tools aka $ARCH-slitaz-*-strip
    2.43 @@ -504,6 +537,18 @@
    2.44  }
    2.45  
    2.46  
    2.47 +# Update installed.cook.diff
    2.48 +
    2.49 +update_installed_cook_diff() {
    2.50 +	# If a cook failed deps are removed.
    2.51 +	cd $root$INSTALLED; ls -1 > $CACHE/installed.cook
    2.52 +	cd $CACHE
    2.53 +	[ "$1" == 'force' -o ! -s '/tmp/installed.cook.diff' ] && \
    2.54 +		busybox diff installed.list installed.cook > /tmp/installed.cook.diff
    2.55 +	deps=$(cat /tmp/installed.cook.diff | grep ^+[a-zA-Z0-9] | wc -l)
    2.56 +}
    2.57 +
    2.58 +
    2.59  # Remove installed deps.
    2.60  
    2.61  remove_deps() {
    2.62 @@ -676,12 +721,7 @@
    2.63  		tazpkg get-install $i --root=$root >/dev/null
    2.64  	done
    2.65  
    2.66 -	# If a cook failed deps are removed.
    2.67 -	cd $root$INSTALLED; ls -1 > $CACHE/installed.cook
    2.68 -	cd $CACHE
    2.69 -	[ ! -s '/tmp/installed.cook.diff' ] && \
    2.70 -		busybox diff installed.list installed.cook > /tmp/installed.cook.diff
    2.71 -	deps=$(cat /tmp/installed.cook.diff | grep ^+[a-zA-Z0-9] | wc -l)
    2.72 +	update_installed_cook_diff
    2.73  
    2.74  	# Get source tarball and make sure we have source dir named:
    2.75  	# $PACKAGE-$VERSION to be standard in receipts. Here we use tar.lzma
    2.76 @@ -749,6 +789,9 @@
    2.77  		testsuite $@ || exit 1
    2.78  		separator; newline
    2.79  	fi
    2.80 +
    2.81 +	fix_desktop_files
    2.82 +	update_installed_cook_diff force
    2.83  }
    2.84  
    2.85  
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/fix-desktop-file	Sat Nov 07 16:00:41 2015 +0200
     3.3 @@ -0,0 +1,304 @@
     3.4 +#!/bin/sh
     3.5 +#
     3.6 +# Description:
     3.7 +# -----------
     3.8 +# There is a utility that allows you to check a lot of mistakes in the
     3.9 +# '.desktop' files: `desktop-file-validate`.
    3.10 +# This utility, `fix-desktop-file`, allows you to correct most errors
    3.11 +# automatically.
    3.12 +# 
    3.13 +# Using:
    3.14 +# -----
    3.15 +#     fix-desktop-file /path/to/desktop-file.desktop
    3.16 +# All the changes are made at the place with the replacement of the original
    3.17 +# file.
    3.18 +# 
    3.19 +# License:
    3.20 +# -------
    3.21 +# `fix-desktop-file` is a part of Cookutils suite for SliTaz GNU/Linux
    3.22 +# and distributed under the same license as the Cookutils.
    3.23 +# 
    3.24 +# Useful links:
    3.25 +# ------------
    3.26 +#   * <http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-1.1.html>
    3.27 +#   * <http://standards.freedesktop.org/menu-spec/menu-spec-1.0.html>
    3.28 +# 
    3.29 +# Author:
    3.30 +# ------
    3.31 +# Aleksej Bobylev <al.bobylev@gmail.com>, November 2015.
    3.32 +
    3.33 +
    3.34 +desktop="$1"
    3.35 +
    3.36 +busybox awk '
    3.37 +BEGIN {
    3.38 +	FS = "=";
    3.39 +	in_section = 0;
    3.40 +	Name = "";
    3.41 +	Comment = "";
    3.42 +	Icon = "";
    3.43 +}
    3.44 +
    3.45 +function handle_cats(x, y,    yy) {
    3.46 +	split(y, yy, ";");
    3.47 +	for(i in yy) {
    3.48 +		if (cats[x] && ! cats[yy[i]]) {
    3.49 +			printf "%s;", yy[i];
    3.50 +			cats[yy[i]] = "printed";
    3.51 +		}
    3.52 +	}
    3.53 +}
    3.54 +
    3.55 +in_section == 1 {
    3.56 +	# remove Version and deprecated keys
    3.57 +	if ($0 ~ /^(Version|Protocols|Extensions|BinaryPattern|MapNotify|Patterns|DefaultApp|MiniIcon|TerminalOptions|Encoding|SwallowTitle|SwallowExec|SortOrder|FilePattern|MultipleArgs)[[:space:]]*=/)
    3.58 +		next;
    3.59 +
    3.60 +	# process Icon
    3.61 +	if ($0 ~ /^Icon[[:space:]]*=/) {
    3.62 +		if (Icon) next;  # Icon already printed
    3.63 +		Icon = gensub(/^[^=]+=[[:space:]]*/, "", "");
    3.64 +		# remove icon extension for non-absolute path
    3.65 +		if ($0 ~ /^Icon[[:space:]]*=[^\/]*$/)
    3.66 +			sub(/\.(png|xpm|svg)$/, "");
    3.67 +	}
    3.68 +
    3.69 +	# fix boolean values
    3.70 +	if ($0 ~ /^(NoDisplay|Hidden|DBusActivatable|Terminal|StartupNotify)[[:space:]]*=/) {
    3.71 +		sub(/0/, "false"); sub(/False/, "false");
    3.72 +		sub(/1/, "true");  sub(/True/,  "true");
    3.73 +	}
    3.74 +
    3.75 +	# process Name
    3.76 +	if ($0 ~ /^Name[[:space:]]*=/) {
    3.77 +		if (Name) next;  # Name already printed
    3.78 +		Name = gensub(/^[^=]+=[[:space:]]*/, "", "");
    3.79 +		print;
    3.80 +		for (i in name) {
    3.81 +			if (name[i] &&
    3.82 +			    name[i] != Name) {  # skip redundant
    3.83 +				printf "Name[%s]=%s\n", i, name[i];
    3.84 +			}
    3.85 +		}
    3.86 +		next;
    3.87 +	}
    3.88 +
    3.89 +	# process localized Names
    3.90 +	if ($0 ~ /^Name\[[^\]+\][[:space:]]*=/) {
    3.91 +		locale = gensub(/^[^\[]*\[([^\]+)\].*$/,    "\\1", "");
    3.92 +		value  = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
    3.93 +		if (name[locale]) next;  # Name[locale] already printed
    3.94 +		name[locale] = value;
    3.95 +		if (Name &&
    3.96 +		    Name != value) {  # skip redundant
    3.97 +			name[locale] = value;
    3.98 +			print;
    3.99 +		}
   3.100 +		if (comment[locale] &&  # print pending Comment[xx]
   3.101 +		    tolower(comment[locale]) != tolower(name[locale]))
   3.102 +			printf "Comment[%s]=%s\n", locale, comment[locale];
   3.103 +		next;
   3.104 +	}
   3.105 +
   3.106 +	# process Comment
   3.107 +	if ($0 ~ /^Comment[[:space:]]*=/) {
   3.108 +		if (Comment) next;  # Comment already printed
   3.109 +		Comment = gensub(/^[^=]+=[[:space:]]*/, "", "");
   3.110 +		if (Comment == Name) {
   3.111 +			printf "%s (*)\n", $0;  # Forgive redundant Comment: Comment[xx] required it
   3.112 +		} else {
   3.113 +			print;
   3.114 +		}
   3.115 +		for (i in comment) {
   3.116 +			if (comment[i] &&
   3.117 +			    tolower(comment[i]) != tolower(Comment) &&
   3.118 +			    tolower(comment[i]) != tolower(name[i])) {  # skip redundant
   3.119 +				printf "Comment[%s]=%s\n", i, comment[i];
   3.120 +			}
   3.121 +		}
   3.122 +		next;
   3.123 +	}
   3.124 +
   3.125 +	# process localized Comments
   3.126 +	if ($0 ~ /^Comment\[[^\]+\][[:space:]]*=/) {
   3.127 +		locale = gensub(/^[^\[]*\[([^\]+)\].*$/,    "\\1", "");
   3.128 +		locomm = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
   3.129 +		if (comment[locale]) next;  # Comment[locale] already printed
   3.130 +		comment[locale] = locomm;
   3.131 +		if (Comment &&  # pending until Comment appear
   3.132 +		    name[locale] &&  # pending until Name[xx] appear
   3.133 +		    tolower(locomm) != tolower(Comment) &&
   3.134 +		    tolower(locomm) != tolower(name[locale])) {  # skip redundant
   3.135 +			comment[locale] = locomm;
   3.136 +			print;
   3.137 +		}
   3.138 +		next;
   3.139 +	}
   3.140 +
   3.141 +	# process Categories list
   3.142 +	if ($0 ~ /^Categories[[:space:]]*=/) {
   3.143 +		value  = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
   3.144 +		split(value, categories, ";");
   3.145 +		printf "Categories=";
   3.146 +		for (i in categories) {
   3.147 +			# skip empty (;;), Application(s), and repeated categories
   3.148 +			if (categories[i] &&
   3.149 +			    categories[i] != "Application" &&
   3.150 +			    categories[i] != "Applications" &&
   3.151 +			    ! cats[categories[i]]) {
   3.152 +				if (categories[i] == "Terminal") categories[i] = "ConsoleOnly"  # Mistake
   3.153 +				if (categories[i] == "Multimedia") categories[i] = "AudioVideo"  # Mistake
   3.154 +				gsub(/ /, "", categories[i]);
   3.155 +				printf "%s;", categories[i];
   3.156 +				cats[categories[i]] = "printed";
   3.157 +			}
   3.158 +		}
   3.159 +		# add main category if needed (http://standards.freedesktop.org/menu-spec/latest/apas02.html)
   3.160 +		handle_cats("Audio",             "AudioVideo");
   3.161 +		handle_cats("Video",             "AudioVideo");
   3.162 +		handle_cats("Building",          "Development");
   3.163 +		handle_cats("Debugger",          "Development");
   3.164 +		handle_cats("IDE",               "Development");
   3.165 +		handle_cats("GUIDesigner",       "Development");
   3.166 +		handle_cats("Profiling",         "Development");
   3.167 +		handle_cats("RevisionControl",   "Development");
   3.168 +		handle_cats("Translation",       "Development");
   3.169 +		handle_cats("Calendar",          "Office");
   3.170 +		handle_cats("ContactManagement", "Office");
   3.171 +		handle_cats("Chart",             "Office");
   3.172 +		handle_cats("Finance",           "Office");
   3.173 +		handle_cats("FlowChart",         "Office");
   3.174 +		handle_cats("PDA",               "Office");
   3.175 +		handle_cats("Presentation",      "Office");
   3.176 +		handle_cats("Spreadsheet",       "Office");
   3.177 +		handle_cats("WordProcessor",     "Office");
   3.178 +		handle_cats("2DGraphics",        "Graphics");
   3.179 +		handle_cats("VectorGraphics",    "Graphics;2DGraphics");
   3.180 +		handle_cats("RasterGraphics",    "Graphics;2DGraphics");
   3.181 +		handle_cats("3DGraphics",        "Graphics");
   3.182 +		handle_cats("Scanning",          "Graphics");
   3.183 +		handle_cats("OCR",               "Graphics;Scanning");
   3.184 +		handle_cats("TextTools",         "Utility");
   3.185 +		handle_cats("DesktopSettings",   "Settings");
   3.186 +		handle_cats("HardwareSettings",  "Settings");
   3.187 +		handle_cats("Printing",          "HardwareSettings;Settings");
   3.188 +		handle_cats("PackageManager",    "Settings");
   3.189 +		handle_cats("Dialup",            "Network");
   3.190 +		handle_cats("InstantMessaging",  "Network");
   3.191 +		handle_cats("Chat",              "Network");
   3.192 +		handle_cats("IRCClient",         "Network");
   3.193 +		handle_cats("Feed",              "Network");
   3.194 +		handle_cats("FileTransfer",      "Network");
   3.195 +		handle_cats("News",              "Network");
   3.196 +		handle_cats("P2P",               "Network");
   3.197 +		handle_cats("RemoteAccess",      "Network");
   3.198 +		handle_cats("Telephony",         "Network");
   3.199 +		handle_cats("TelephonyTools",    "Utility");
   3.200 +		handle_cats("VideoConference",   "Network");
   3.201 +		handle_cats("WebBrowser",        "Network");
   3.202 +		handle_cats("Midi",              "AudioVideo;Audio");
   3.203 +		handle_cats("Mixer",             "AudioVideo;Audio");
   3.204 +		handle_cats("Sequencer",         "AudioVideo;Audio");
   3.205 +		handle_cats("Tuner",             "AudioVideo;Audio");
   3.206 +		handle_cats("TV",                "AudioVideo;Video");
   3.207 +		handle_cats("DiscBurning",       "AudioVideo");
   3.208 +		handle_cats("ActionGame",        "Game");
   3.209 +		handle_cats("AdventureGame",     "Game");
   3.210 +		handle_cats("ArcadeGame",        "Game");
   3.211 +		handle_cats("BoardGame",         "Game");
   3.212 +		handle_cats("BlocksGame",        "Game");
   3.213 +		handle_cats("CardGame",          "Game");
   3.214 +		handle_cats("KidsGame",          "Game");
   3.215 +		handle_cats("LogicGame",         "Game");
   3.216 +		handle_cats("RolePlaying",       "Game");
   3.217 +		handle_cats("Shooter",           "Game");
   3.218 +		handle_cats("Simulation",        "Game");
   3.219 +		handle_cats("SportsGame",        "Game");
   3.220 +		handle_cats("StrategyGame",      "Game");
   3.221 +		handle_cats("Archiving",         "Utility");
   3.222 +		handle_cats("Compression",       "Utility;Archiving");
   3.223 +		handle_cats("FileManager",       "System;FileTools");
   3.224 +		handle_cats("TerminalEmulator",  "System");
   3.225 +		handle_cats("Filesystem",        "System");
   3.226 +		handle_cats("Calculator",        "Utility");
   3.227 +		handle_cats("Clock",             "Utility");
   3.228 +		handle_cats("TextEditor",        "Utility");
   3.229 +		handle_cats("KDE",               "Qt");
   3.230 +		handle_cats("GNOME",             "GTK");
   3.231 +		handle_cats("XFCE",              "GTK");
   3.232 +
   3.233 +		printf "\n";
   3.234 +		next;
   3.235 +	}
   3.236 +
   3.237 +	# process MimeType list
   3.238 +	if ($0 ~ /^MimeType[[:space:]]*=/) {
   3.239 +		value = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
   3.240 +		value = gensub(/x-directory\/gnome-default-handler/, "inode/directory", "g", value);
   3.241 +		value = gensub(/x-directory\/normal/, "inode/directory", "g", value);
   3.242 +		gsub(/ /, "", value);
   3.243 +		split(value, mimetype, ";");
   3.244 +		printf "MimeType=";
   3.245 +		for (i in mimetype) {
   3.246 +			# skip empty (;;), and repeated mimetypes
   3.247 +			if (mimetype[i] &&
   3.248 +			    ! mimes[mimetype[i]]) {
   3.249 +				printf "%s;", mimetype[i];
   3.250 +				mimes[mimetype[i]] = "printed";
   3.251 +			}
   3.252 +		}
   3.253 +		printf "\n";
   3.254 +		next;
   3.255 +	}
   3.256 +
   3.257 +	# process Keywords
   3.258 +	if ($0 ~ /^Keywords[[:space:]]*=/) {
   3.259 +		value = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
   3.260 +		split(value, keywords, ";");
   3.261 +		printf "Keywords=";
   3.262 +		for (i in keywords) {
   3.263 +			# skip empty (;;), and repeated keywords
   3.264 +			if (keywords[i] &&
   3.265 +			    ! keys[keywords[i]]) {
   3.266 +				printf "%s;", keywords[i];
   3.267 +				keys[keywords[i]] = "printed";
   3.268 +			}
   3.269 +		}
   3.270 +		printf "\n";
   3.271 +		delete keys;
   3.272 +		next;
   3.273 +	}
   3.274 +
   3.275 +	# process localized Keywords
   3.276 +	if ($0 ~ /^Keywords\[[^\]+\][[:space:]]*=/) {
   3.277 +		locale = gensub(/^[^\[]*\[([^\]+)\].*$/,    "\\1", "");
   3.278 +		lokeys = gensub(/^[^=]*=[[:space:]]*(.*)$/, "\\1", "");
   3.279 +		split(lokeys, keywords, ";");
   3.280 +		printf "Keywords[%s]=", locale;
   3.281 +		for (i in keywords) {
   3.282 +			# skip empty (;;), and repeated keywords
   3.283 +			if (keywords[i] &&
   3.284 +			    ! keys[keywords[i]]) {
   3.285 +				printf "%s;", keywords[i];
   3.286 +				keys[keywords[i]] = "printed";
   3.287 +			}
   3.288 +		}
   3.289 +		printf "\n";
   3.290 +		delete keys;
   3.291 +		next;
   3.292 +	}
   3.293 +
   3.294 +}
   3.295 +
   3.296 +/^\[/ {
   3.297 +	in_section = 0;
   3.298 +}
   3.299 +/^\[Desktop Entry\]/ {
   3.300 +	in_section = 1;
   3.301 +}
   3.302 +{
   3.303 +	print;
   3.304 +}
   3.305 +' "$desktop" > "$desktop.$$"
   3.306 +
   3.307 +mv -f "$desktop.$$" "$desktop"