@@ -84,42 +84,76 @@ def __exit__(self, *args):
84
84
# Uninstall script {{{
85
85
UNINSTALL = '''\
86
86
#!{python}
87
+ from __future__ import print_function, unicode_literals
87
88
euid = {euid}
88
89
89
90
import os, subprocess, shutil
90
91
91
- if os.geteuid() != euid:
92
- print 'WARNING: uninstaller must be run as', euid, 'to remove all files'
92
+ try:
93
+ raw_input
94
+ except NameError:
95
+ raw_input = input
93
96
94
- for x in {manifest!r}:
95
- if not os.path.exists(x): continue
96
- print 'Removing', x
97
+ if os.geteuid() != euid:
98
+ print ('The installer was last run as user id:', euid, 'To remove all files you must run the uninstaller as the same user')
99
+ if raw_input('Proceed anyway? [y/n]:').lower() != 'y':
100
+ raise SystemExit(1)
101
+
102
+ frozen_path = {frozen_path!r}
103
+ if not frozen_path or not os.path.exists(os.path.join(frozen_path, 'resources', 'calibre-mimetypes.xml')):
104
+ frozen_path = None
105
+
106
+ for x in tuple({manifest!r}) + tuple({appdata_resources!r}) + (os.path.abspath(__file__), __file__, frozen_path):
107
+ if not x or not os.path.exists(x):
108
+ continue
109
+ print ('Removing', x)
97
110
try:
98
111
if os.path.isdir(x):
99
112
shutil.rmtree(x)
100
113
else:
101
114
os.unlink(x)
102
115
except Exception as e:
103
- print 'Failed to delete', x
104
- print '\t ', e
116
+ print ( 'Failed to delete', x)
117
+ print ( '\t ', e)
105
118
106
119
icr = {icon_resources!r}
107
- for context, name, size in icr:
120
+ mimetype_icons = []
121
+
122
+ def remove_icon(context, name, size, update=False):
108
123
cmd = ['xdg-icon-resource', 'uninstall', '--context', context, '--size', size, name]
109
- if (context, name) != icr[-1] :
124
+ if not update :
110
125
cmd.insert(2, '--noupdate')
126
+ print ('Removing icon:', name, 'from context:', context, 'at size:', size)
111
127
ret = subprocess.call(cmd)
112
128
if ret != 0:
113
- print 'WARNING: Failed to remove icon', name
129
+ print ('WARNING: Failed to remove icon', name)
130
+
131
+ for i, (context, name, size) in enumerate(icr):
132
+ if context == 'mimetypes':
133
+ mimetype_icons.append((name, size))
134
+ continue
135
+ remove_icon(context, name, size, update=i == len(icr) - 1)
114
136
115
137
mr = {menu_resources!r}
116
138
for f in mr:
117
139
cmd = ['xdg-desktop-menu', 'uninstall', f]
140
+ print ('Removing desktop file:', f)
118
141
ret = subprocess.call(cmd)
119
142
if ret != 0:
120
- print 'WARNING: Failed to remove menu item', f
143
+ print ( 'WARNING: Failed to remove menu item', f)
121
144
122
- os.remove(os.path.abspath(__file__))
145
+ for f in {mime_resources!r}:
146
+ cmd = ['xdg-mime', 'uninstall', f]
147
+ print ('Removing mime resource:', os.path.basename(f))
148
+ ret = subprocess.call(cmd)
149
+ if ret != 0:
150
+ print ('WARNING: Failed to remove mime resource', f)
151
+
152
+ print ()
153
+
154
+ if mimetype_icons and raw_input('Remove the ebook format icons? [y/n]:').lower() in ['', 'y']:
155
+ for i, (name, size) in enumerate(mimetype_icons):
156
+ remove_icon('mimetypes', name, size, update=i == len(mimetype_icons) - 1)
123
157
'''
124
158
125
159
# }}}
@@ -447,6 +481,7 @@ def __init__(self, opts, info=prints, warn=None, manifest=None):
447
481
self .icon_resources = []
448
482
self .menu_resources = []
449
483
self .mime_resources = []
484
+ self .appdata_resources = []
450
485
if islinux or isbsd :
451
486
self .setup_completion ()
452
487
if islinux or isbsd :
@@ -472,9 +507,12 @@ def __init__(self, opts, info=prints, warn=None, manifest=None):
472
507
473
508
def create_uninstaller (self ):
474
509
dest = os .path .join (self .opts .staging_bindir , 'calibre-uninstall' )
475
- raw = UNINSTALL .format (python = os .path .abspath (sys .executable ), euid = os .geteuid (),
476
- manifest = self .manifest , icon_resources = self .icon_resources ,
477
- menu_resources = self .menu_resources )
510
+ self .info ('Creating un-installer:' , dest )
511
+ raw = UNINSTALL .format (
512
+ python = '/usr/bin/python' , euid = os .geteuid (),
513
+ manifest = self .manifest , icon_resources = self .icon_resources ,
514
+ mime_resources = self .mime_resources , menu_resources = self .menu_resources ,
515
+ appdata_resources = self .appdata_resources , frozen_path = getattr (sys , 'frozen_path' , None ))
478
516
try :
479
517
with open (dest , 'wb' ) as f :
480
518
f .write (raw )
@@ -677,13 +715,13 @@ def setup_desktop_integration(self): # {{{
677
715
self .icon_resources .append (('mimetypes' , 'application-x-mobi8-ebook' , '128' ))
678
716
render_img ('lt.png' , 'calibre-gui.png' , width = 256 , height = 256 )
679
717
cc ('xdg-icon-resource install --noupdate --size 256 calibre-gui.png calibre-gui' , shell = True )
680
- self .icon_resources .append (('apps' , 'calibre-gui' , '128 ' ))
681
- render_img ('viewer.png' , 'calibre-viewer.png' )
682
- cc ('xdg-icon-resource install --size 128 calibre-viewer.png calibre-viewer' , shell = True )
683
- self .icon_resources .append (('apps' , 'calibre-viewer' , '128 ' ))
684
- render_img ('tweak.png' , 'calibre-ebook-edit.png' )
685
- cc ('xdg-icon-resource install --size 128 calibre-ebook-edit.png calibre-ebook-edit' , shell = True )
686
- self .icon_resources .append (('apps' , 'calibre-ebook-edit' , '128 ' ))
718
+ self .icon_resources .append (('apps' , 'calibre-gui' , '256 ' ))
719
+ render_img ('viewer.png' , 'calibre-viewer.png' , width = 256 , height = 256 )
720
+ cc ('xdg-icon-resource install --size 256 calibre-viewer.png calibre-viewer' , shell = True )
721
+ self .icon_resources .append (('apps' , 'calibre-viewer' , '256 ' ))
722
+ render_img ('tweak.png' , 'calibre-ebook-edit.png' , width = 256 , height = 256 )
723
+ cc ('xdg-icon-resource install --size 256 calibre-ebook-edit.png calibre-ebook-edit' , shell = True )
724
+ self .icon_resources .append (('apps' , 'calibre-ebook-edit' , '256 ' ))
687
725
688
726
mimetypes = set ([])
689
727
for x in all_input_formats ():
@@ -731,13 +769,11 @@ def write_mimetypes(f):
731
769
self .menu_resources .append (x )
732
770
ak = x .partition ('.' )[0 ]
733
771
if ak in APPDATA and os .access (appdata , os .W_OK ):
734
- write_appdata (ak , APPDATA [ak ], appdata , translators )
772
+ self . appdata_resources . append ( write_appdata (ak , APPDATA [ak ], appdata , translators ) )
735
773
cc (['xdg-desktop-menu' , 'forceupdate' ])
736
- f = open ('calibre-mimetypes.xml' , 'wb' )
737
- f .write (MIME )
738
- f .close ()
739
- self .mime_resources .append ('calibre-mimetypes.xml' )
740
- cc ('xdg-mime install ./calibre-mimetypes.xml' , shell = True )
774
+ MIME = P ('calibre-mimetypes.xml' )
775
+ self .mime_resources .append (MIME )
776
+ cc (['xdg-mime' , 'install' , MIME ])
741
777
except Exception :
742
778
if self .opts .fatal_errors :
743
779
raise
@@ -972,51 +1008,6 @@ def write_appdata(key, entry, base, translators):
972
1008
return fpath
973
1009
974
1010
975
- MIME = '''\
976
- <?xml version="1.0"?>
977
- <mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
978
- <mime-type type="application/x-sony-bbeb">
979
- <comment>SONY E-book compiled format</comment>
980
- <glob pattern="*.lrf"/>
981
- </mime-type>
982
- <mime-type type="application/epub+zip">
983
- <comment>EPUB ebook format</comment>
984
- <glob pattern="*.epub"/>
985
- </mime-type>
986
- <mime-type type="text/lrs">
987
- <comment>SONY E-book source format</comment>
988
- <glob pattern="*.lrs"/>
989
- </mime-type>
990
- <mime-type type="application/x-mobipocket-ebook">
991
- <comment>Amazon Mobipocket e-book format</comment>
992
- <sub-class-of type="application/x-palm-database"/>
993
- <glob pattern="*.azw"/>
994
- </mime-type>
995
- <mime-type type="application/x-topaz-ebook">
996
- <comment>Amazon Topaz ebook format</comment>
997
- <glob pattern="*.tpz"/>
998
- <glob pattern="*.azw1"/>
999
- </mime-type>
1000
- <mime-type type="application/x-kindle-application">
1001
- <comment>Amazon Kindle Application (Kindlet)</comment>
1002
- <sub-class-of type="application/x-java-archive"/>
1003
- <glob pattern="*.azw2"/>
1004
- </mime-type>
1005
- <mime-type type="application/x-mobipocket-subscription">
1006
- <comment>Amazon Mobipocket ebook newspaper format</comment>
1007
- <sub-class-of type="application/x-mobipocket-ebook"/>
1008
- <!-- Technically, this depends on the cdeType (NWPR or MAGZ), but since EXTH headers have a variable length, it's tricky to probe via magic... -->
1009
- <alias type="application/x-mobipocket-subscription-magazine"/>
1010
- <glob pattern="*.pobi"/>
1011
- </mime-type>
1012
- <mime-type type="application/x-mobi8-ebook">
1013
- <comment>Amazon KF8 ebook format</comment>
1014
- <sub-class-of type="application/x-palm-database"/>
1015
- <glob pattern="*.azw3"/>
1016
- </mime-type>
1017
- </mime-info>
1018
- '''
1019
-
1020
1011
def render_img (image , dest , width = 128 , height = 128 ):
1021
1012
from PyQt4 .Qt import QImage , Qt
1022
1013
img = QImage (I (image )).scaled (width , height , Qt .IgnoreAspectRatio , Qt .SmoothTransformation )
0 commit comments