Merge lp:~mvo/deb-thumbnailer/mvo into lp:deb-thumbnailer

Proposed by Michael Vogt
Status: Merged
Approved by: Alex Eftimie
Approved revision: 63
Merged at revision: 61
Proposed branch: lp:~mvo/deb-thumbnailer/mvo
Merge into: lp:deb-thumbnailer
Diff against target: 356 lines (+152/-54)
3 files modified
Makefile (+3/-0)
deb-thumbnailer (+97/-54)
tests/test_thumbnailer.py (+52/-0)
To merge this branch: bzr merge lp:~mvo/deb-thumbnailer/mvo
Reviewer Review Type Date Requested Status
George Dumitrescu Approve
Alex Eftimie Approve
Review via email: mp+42658@code.launchpad.net

Commit message

ok

Description of the change

Hi,

I like this project a lot, the idea is just great. While looking at the code I noticed
that there are some bits and piece as could be cleaned up. Like the use of os.system()
can be dangerous because its directly feed into a shell. The subprocess.call() is a
better option. If you are ok with my changes I will look a bit more and see what else
will benefit from cleanup so that we can tweak it so that its ready for inclusion
into the archive.

Thanks,
 Michael

To post a comment you must log in.
Revision history for this message
Alex Eftimie (alexeftimie) wrote :

Looks fine to me.

review: Approve
lp:~mvo/deb-thumbnailer/mvo updated
64. By Michael Vogt

add simple test/ dir

65. By Michael Vogt

more tests, seperate out get_icons_from_deb()

Revision history for this message
George Dumitrescu (geod) wrote :

ok

review: Approve
Revision history for this message
Michael Vogt (mvo) wrote :

Thanks a lot for the merge! I'm a bit short on time currently unfortunately, but I plan to add more test :)

Cheers,
 Michael

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2010-07-01 06:04:24 +0000
+++ Makefile 2010-12-06 14:29:01 +0000
@@ -3,6 +3,9 @@
3clean:3clean:
4 rm -fr build4 rm -fr build
55
6test:
7 (set -e; cd tests; for f in *.py; do python $$f; done)
8
6pack:9pack:
7 tar czvf deb-thumbnailer.tgz deb-thumbnailer install README INSTALL COPYING AUTHORS share debian make-deb Makefile10 tar czvf deb-thumbnailer.tgz deb-thumbnailer install README INSTALL COPYING AUTHORS share debian make-deb Makefile
811
912
=== modified file 'deb-thumbnailer'
--- deb-thumbnailer 2010-08-30 18:48:25 +0000
+++ deb-thumbnailer 2010-12-06 14:29:01 +0000
@@ -5,55 +5,66 @@
5__date__ ="$Jun 28, 2010 05:00:40 PM$"5__date__ ="$Jun 28, 2010 05:00:40 PM$"
66
7from PIL import Image7from PIL import Image
8import tempfile8
9import os9import os
10import glob10import glob
11import shutil11import shutil
12import string
13import subprocess
12import sys14import sys
13import subprocess15
16import tempfile
14import urllib17import urllib
18
15import gtk19import gtk
16import gconf20import gconf
17import hashlib21import hashlib
18import logging22import logging
23import xdg.BaseDirectory
1924
20GENERIC_APP=''
21GENERIC_LIB=''
22VERSION='0.8.2'25VERSION='0.8.2'
23CONFIG_DIR = '/apps/deb-thumbnailer'26CONFIG_DIR = '/apps/deb-thumbnailer'
24ICON_THEME = gtk.icon_theme_get_default()27ICON_THEME = gtk.icon_theme_get_default()
25HOME_DIR = os.getenv("HOME")
26DT_DIR = HOME_DIR + '/.deb-thumbnailer'
27LOG_FILENAME = '/tmp/deb-thumbnailer.log'
28HASH_NAME = ''28HASH_NAME = ''
29DEB_FILE = ''29DEB_FILE = ''
30MD = hashlib.md5()30MD = hashlib.md5()
31logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)31
3232# special names to watch for
33def get_config():33SPECIAL_ICON_NAMES = [ "opera-browser",
34 "apps/opera.png",
35 "product_logo_128.png",
36 "AdobeAIR.png",
37 "AdobeReader[0-9]*\.png"
38 ]
39
40
41#LOG_FILENAME = '/tmp/deb-thumbnailer.log'
42#logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
43
44def pkgname_from_deb(debfile):
45 """ return the binary package name of the given deb """
46 pkgname = subprocess.Popen(["dpkg-deb","-f", debfile, "Package"],
47 stdout=subprocess.PIPE).communicate()[0].strip()
48 return pkgname
49
50def get_config_icon_default():
34 """ get gconf configuration """51 """ get gconf configuration """
35 gclient = gconf.client_get_default()52 gclient = gconf.client_get_default()
36 config_value = gclient.get(CONFIG_DIR+'/icon_default')53 return gclient.get_bool(CONFIG_DIR+'/icon_default')
37 try:
38 return config_value.get_bool()
39 except:
40 return False
41 54
42def set_config(setit):55def set_config_icon_default(new_value):
43 """ set gconf configuration """56 """ set gconf configuration """
44 gclient = gconf.client_get_default()57 gclient = gconf.client_get_default()
45 gvalue = gconf.Value(gconf.VALUE_BOOL)58 gclient.set_bool(CONFIG_DIR+'/icon_default', new_value)
46 gvalue.set_bool(setit)
47 gclient.set(CONFIG_DIR+'/icon_default', gvalue)
4859
49def pkg_overlay(background, source, destination, percent=0.5, size=48):60def pkg_overlay(background, source, destination, percent=0.5, size=48):
50 """ Merges background with source scalled by percent, aligned bottom-right 61 """ Merges background with source scalled by percent, aligned bottom-right
51 Saves the result into destination file62 Saves the result into destination file
52 """63 """
53 if not get_config():64 if not get_config_icon_default():
54 background, source = source, background65 background, source = source, background
55 bg = Image.open(background).convert('RGBA')66 bg = Image.open(background).convert('RGBA')
56 if not get_config():67 if not get_config_icon_default():
57 bg = bg.resize((size, size), Image.ANTIALIAS)68 bg = bg.resize((size, size), Image.ANTIALIAS)
5869
59 if source != '':70 if source != '':
@@ -66,29 +77,63 @@
66 77
67 bg.save(destination, 'PNG')78 bg.save(destination, 'PNG')
6879
80def get_filelist_from_deb(debfile):
81 """ return all files inside a deb as a string list """
82 # a alternative is apt_inst.DebFile()
83 p1 = subprocess.Popen(["dpkg", "--fsys-tarfile", debfile],
84 stdout=subprocess.PIPE)
85 p2 = subprocess.Popen(["tar", "tf","-"],
86 stdin=p1.stdout,
87 stdout=subprocess.PIPE)
88 return map(string.strip, p2.stdout.readlines())
89
90def extract_file_from_deb(debfile, filename, targetdir="."):
91 """ extract the given filename into targetdir """
92 # a alternative is apt_inst.DebFile() (again)
93 p1 = subprocess.Popen(["dpkg", "--fsys-tarfile", debfile],
94 stdout=subprocess.PIPE)
95 p2 = subprocess.Popen(["tar", "xf","-", filename],
96 stdin=p1.stdout,
97 stdout=subprocess.PIPE,
98 cwd=targetdir)
99 return p2.wait()
100
101def get_icons_from_deb(debfile, tmpdir="."):
102 logging.debug("get_icons_from_deb() %s in %s" % (debfile, tmpdir))
103 icons = []
104 debfile = os.path.abspath(debfile)
105 if not os.path.exists(debfile):
106 raise IOError("file '%s' not found" % debfile)
107 pname = pkgname_from_deb(debfile)
108 for line in get_filelist_from_deb(debfile):
109 # FIXME: also test for SPECIAL_ICON_NAMES
110 if (line.startswith("./usr/share/icons") or
111 line.startswith("./usr/share/pixmaps")):
112 icons.append(line)
113 icons.sort()
114 logging.debug("found icons: '%s'" % icons)
115 res = extract_file_from_deb(debfile, icons[-1], tmpdir)
116 return icons
117
69def process_deb(debfile, size=48):118def process_deb(debfile, size=48):
119 """ Unpacks a .deb file and returns the icon path """
70 global HASH_NAME120 global HASH_NAME
71 global DEB_FILE121 global DEB_FILE
72 """ Unpacks a .deb file and returns the icon path """122
73 curdir = os.getcwd()123 curdir = os.getcwd()
74 tmpdir = tempfile.mkdtemp('-deb-thumbnailer')124 tmpdir = tempfile.mkdtemp('-deb-thumbnailer')
75 icons = []125 icons = []
76 svg = False126 svg = False
77 DEB_FILE = debfile127 DEB_FILE = debfile
78 128
79 # Get package name safely129 # Get package name safely (read from debian/control)
80 try:130 debfileName = os.path.basename(debfile)
81 pname = os.path.split(debfile)[1]131 pname = pkgname_from_deb(debfile)
82 debfileName = pname
83 pname = pname.split('_')[0]
84 except:
85 logging.debug("Failed to obtain %s filename" % debfile)
86 pname = debfile
87 debfileName = pname
88 132
133 # hash it
89 MD.update(debfileName)134 MD.update(debfileName)
90 HASH_NAME = MD.hexdigest()135 HASH_NAME = MD.hexdigest()
91 if not get_config():136 if not get_config_icon_default():
92 HASH_NAME = HASH_NAME + '1'137 HASH_NAME = HASH_NAME + '1'
93 # asking system for app icon (faster)138 # asking system for app icon (faster)
94 if pname == 'deb-thumbnailer':139 if pname == 'deb-thumbnailer':
@@ -103,25 +148,20 @@
103 if not len(icons) == 0:148 if not len(icons) == 0:
104 iconFile = os.path.split(icons[1])[1]149 iconFile = os.path.split(icons[1])[1]
105 iconExt = os.path.splitext(iconFile)[1]150 iconExt = os.path.splitext(iconFile)[1]
106 os.system("cp %s %s" % (icons[1], tmpdir + '/' + iconFile))151 shutil.copy(icons[1], os.path.join(tmpdir, iconFile))
107 icons[1] = iconFile152 icons[1] = iconFile
108 if iconExt == '.svg':153 if iconExt == '.svg':
109 svg = True154 svg = True
110 155
111 # searching in package156 # searching in package
112 if len(icons) == 0:157 if len(icons) == 0:
113 os.chdir(tmpdir)158 icons = get_icons_from_deb(debfile, tmpdir)
114 if pname == "opera-browser":
115 icons = subprocess.Popen('ar -x "%s"; tar -tf data.tar.* | egrep "\.png$|\.svg$|\.xpm$" | egrep "(opera\-browser)|apps/opera.png$"' % debfile, shell=True, stdout=subprocess.PIPE).stdout.read().split("\n")
116 else:
117 icons = subprocess.Popen('ar -x "%s"; tar -tf data.tar.* | egrep "\.png$|\.svg$|\.xpm$" | egrep "(usr/share/icons|usr/share/pixmaps|product_logo_128\.png|[0-9]/AdobeReader[0-9]\.png|[0-9]/AdobeAIR.png)"' % debfile, shell=True, stdout=subprocess.PIPE).stdout.read().split("\n")
118 icons.sort()
119 os.system('tar -xf data.tar.* "%s"' % icons[-1])
120 # Search for SVG icons159 # Search for SVG icons
121 iconFile = os.path.split(icons[-1].replace("./", ""))[1]160 iconFile = os.path.split(icons[-1].replace("./", ""))[1]
122 iconExt = os.path.splitext(iconFile)[1]161 iconExt = os.path.splitext(iconFile)[1]
123 if iconExt == ".svg":162 if iconExt == ".svg":
124 svg = True163 svg = True
164
125 # Go back 165 # Go back
126 os.chdir(curdir)166 os.chdir(curdir)
127 if len(icons) > 1:167 if len(icons) > 1:
@@ -134,7 +174,7 @@
134 shutil.copyfile(tmpdir + '/' + icon.replace("./", ""), tmpfile)174 shutil.copyfile(tmpdir + '/' + icon.replace("./", ""), tmpfile)
135 # convert SVG175 # convert SVG
136 if svg == True:176 if svg == True:
137 os.system("rsvg-convert %s -o %s.png" % (tmpfile, tmpfile))177 subprocess.call(["rsvg-convert", tmpfile, "-o", "%s.png" % tmpfile])
138 if os.path.exists(tmpfile):178 if os.path.exists(tmpfile):
139 os.unlink(tmpfile)179 os.unlink(tmpfile)
140 tmpfile = '%s.png' % tmpfile180 tmpfile = '%s.png' % tmpfile
@@ -152,10 +192,11 @@
152 pkgIconExt = os.path.splitext(pkgIcon)[1]192 pkgIconExt = os.path.splitext(pkgIcon)[1]
153 # TODO: ask theme for png directly | INFO: not all themes provide png193 # TODO: ask theme for png directly | INFO: not all themes provide png
154 if pkgIconExt == '.svg':194 if pkgIconExt == '.svg':
155 if os.path.exists('/tmp/x-deb-%d.png' % size):195 target = tempfile.NamedTemporaryFile(prefix="x-deb-%d" % size)
156 os.unlink('/tmp/x-deb-%d.png' % size)196 if os.path.exists(target):
157 os.system("rsvg-convert %s -w %d -h %d -o /tmp/x-deb-%d.png" % (pkgIcon, size, size, size))197 os.unlink(target)
158 return "/tmp/x-deb-%d.png" % size198 subprocess.call(["rsvg-convert", pkgIcon, "-w", size, "-h", size, "-o", target])
199 return target
159 else:200 else:
160 return pkgIcon201 return pkgIcon
161202
@@ -164,12 +205,12 @@
164 switch = subprocess.Popen('zenity --list --radiolist --column="" --column="type" TRUE "Package icon in background (default)" FALSE "Application icon in background" --title="Icon type"', shell=True, stdout=subprocess.PIPE).stdout.read().split('\n')[0]205 switch = subprocess.Popen('zenity --list --radiolist --column="" --column="type" TRUE "Package icon in background (default)" FALSE "Application icon in background" --title="Icon type"', shell=True, stdout=subprocess.PIPE).stdout.read().split('\n')[0]
165 config_change = False206 config_change = False
166 if switch == "Package icon in background (default)":207 if switch == "Package icon in background (default)":
167 if get_config() != True:208 if get_config_icon_default() != True:
168 set_config(True)209 set_config_icon_default(True)
169 config_change = True210 config_change = True
170 elif switch == "Application icon in background":211 elif switch == "Application icon in background":
171 if get_config() != False:212 if get_config_icon_default() != False:
172 set_config(False)213 set_config_icon_default(False)
173 config_change = True214 config_change = True
174 if config_change:215 if config_change:
175 print "Refreshing thumbnails cache ..."216 print "Refreshing thumbnails cache ..."
@@ -182,7 +223,7 @@
182 reset_icons()223 reset_icons()
183 thumbdir = HOME_DIR + '/.thumbnails'224 thumbdir = HOME_DIR + '/.thumbnails'
184 if os.path.isdir(thumbdir):225 if os.path.isdir(thumbdir):
185 os.system("rm -rf %s" % thumbdir)226 shutil.rmtree(thumbdir)
186227
187def reset_icons():228def reset_icons():
188 """ reseting icons to .deb only in home folder """229 """ reseting icons to .deb only in home folder """
@@ -192,13 +233,14 @@
192 if os.path.exists(debs[i]):233 if os.path.exists(debs[i]):
193 info = subprocess.Popen("gvfs-info -a metadata::custom-icon \"%s\"" % debs[i], shell=True, stdout=subprocess.PIPE).stdout.read().split("\n")[1]234 info = subprocess.Popen("gvfs-info -a metadata::custom-icon \"%s\"" % debs[i], shell=True, stdout=subprocess.PIPE).stdout.read().split("\n")[1]
194 if info != '':235 if info != '':
195 os.system('gvfs-set-attribute "%s" -t unset metadata::custom-icon' % debs[i])236 subprocess.call(["gvfs-set-attribute", debs[i], "-t", "unset", "metadata::custom-icon"])
196237
197if __name__ == "__main__":238if __name__ == "__main__":
198 global DEB_NAME
199 proceed = False239 proceed = False
240 DT_DIR = os.path.join(xdg.BaseDirectory.xdg_cache_home, "deb-thumbnailer")
200 if not os.path.exists(DT_DIR):241 if not os.path.exists(DT_DIR):
201 os.makedirs(DT_DIR)242 os.makedirs(DT_DIR)
243 # ???
202 if len(sys.argv) == 4:244 if len(sys.argv) == 4:
203 try:245 try:
204 size = int(sys.argv[3])246 size = int(sys.argv[3])
@@ -219,7 +261,8 @@
219 shutil.copy(output, DT_DIR + '/' + HASH_NAME + '.png')261 shutil.copy(output, DT_DIR + '/' + HASH_NAME + '.png')
220 dt_path = DT_DIR + '/' + HASH_NAME + '.png'262 dt_path = DT_DIR + '/' + HASH_NAME + '.png'
221 if os.path.exists(dt_path):263 if os.path.exists(dt_path):
222 os.system("gvfs-set-attribute \"%s\" metadata::custom-icon file://%s" % (DEB_FILE, dt_path))264 subprocess.call(["gvfs-set-attribute", DEB_FILE, "metadata::custom-icon", "file://%s" % dt_path])
265 # options?
223 elif len(sys.argv) == 2:266 elif len(sys.argv) == 2:
224 if sys.argv[1] == '--switch':267 if sys.argv[1] == '--switch':
225 icon_switch()268 icon_switch()
@@ -240,7 +283,7 @@
240 proceed = True283 proceed = True
241 else:284 else:
242 logging.debug("File %s is not an .deb file" % os.path.split(input)[1])285 logging.debug("File %s is not an .deb file" % os.path.split(input)[1])
243 os.system('zenity --error --title="Deb-Thumbnailer: Error" --text="File \'%s\' is not an .deb file"' % os.path.split(input)[1])286 subprocess.call(['zenity', '--error', '--title=Deb-Thumbnailer: Error', '--text=File \'%s\' is not an .deb file' % os.path.split(input)[1]])
244 287
245 if proceed:288 if proceed:
246 if not os.path.exists(input):289 if not os.path.exists(input):
247290
=== added symlink 'deb_thumbnailer.py'
=== target is u'deb-thumbnailer'
=== added directory 'tests'
=== added file 'tests/test_thumbnailer.py'
--- tests/test_thumbnailer.py 1970-01-01 00:00:00 +0000
+++ tests/test_thumbnailer.py 2010-12-06 14:29:01 +0000
@@ -0,0 +1,52 @@
1#!/usr/bin/python
2
3
4import sys
5sys.path.insert(0,"../")
6
7import glob
8import os
9import hashlib
10import subprocess
11import unittest
12import urllib
13
14from deb_thumbnailer import (process_deb, get_icons_from_deb, pkgname_from_deb,
15 get_filelist_from_deb)
16
17class TestDebThumbnailer(unittest.TestCase):
18 """ tests the xapian database """
19
20 def setUp(self):
21 gcalctool_url = "http://archive.ubuntu.com/ubuntu/pool/main/g/gcalctool/gcalctool_5.30.0.is.5.28.2-0ubuntu2_i386.deb"
22 self.gcalctool = os.path.basename(gcalctool_url)
23 if not os.path.exists(self.gcalctool):
24 (filename, res) = urllib.urlretrieve(
25 gcalctool_url, filename=self.gcalctool)
26 m = hashlib.md5()
27 m.update(open(self.gcalctool).read())
28 self.assertEqual(m.hexdigest(), "5914fe02d32f9153eb2994dd6c80c8f6")
29
30 def test_process_deb(self):
31 # this url is valid until 2015
32 icon = process_deb(self.gcalctool)
33 # ensure we get a icon
34 self.assertTrue(os.path.exists(icon))
35 self.assertTrue(os.path.getsize(icon) > 0)
36
37 def test_get_icons_from_deb(self):
38 import tempfile
39 tmpdir = tempfile.mkdtemp()
40 get_icons_from_deb(self.gcalctool, tmpdir)
41
42 def test_pkgname_from_deb(self):
43 self.assertEqual(pkgname_from_deb(self.gcalctool), "gcalctool")
44
45 def test_filelist_from_deb(self):
46 flist = get_filelist_from_deb(self.gcalctool)
47 self.assertTrue("./usr/share/omf/gcalctool/gcalctool-bg.omf" in flist)
48
49if __name__ == "__main__":
50 import logging
51 logging.basicConfig(level=logging.DEBUG)
52 unittest.main()

Subscribers

People subscribed via source and target branches