77
77
elif os.path.exists(path):
78
with open(path, 'r+b') as f:
79
with open(path, 'r+b') as f:
84
except EnvironmentError as e:
85
if e.errno != errno.EACCES:
84
88
# Uninstall script {{{
91
from __future__ import print_function, unicode_literals
89
94
import os, subprocess, shutil
91
101
if os.geteuid() != euid:
92
print 'WARNING: uninstaller must be run as', euid, 'to remove all files'
94
for x in {manifest!r}:
95
if not os.path.exists(x): continue
102
print ('The installer was last run as user id:', euid, 'To remove all files you must run the uninstaller as the same user')
103
if raw_input('Proceed anyway? [y/n]:').lower() != 'y':
106
frozen_path = {frozen_path!r}
107
if not frozen_path or not os.path.exists(os.path.join(frozen_path, 'resources', 'calibre-mimetypes.xml')):
110
for f in {mime_resources!r}:
111
cmd = ['xdg-mime', 'uninstall', f]
112
print ('Removing mime resource:', os.path.basename(f))
113
ret = subprocess.call(cmd, shell=False)
115
print ('WARNING: Failed to remove mime resource', f)
117
for x in tuple({manifest!r}) + tuple({appdata_resources!r}) + (os.path.abspath(__file__), __file__, frozen_path):
118
if not x or not os.path.exists(x):
120
print ('Removing', x)
98
122
if os.path.isdir(x):
102
126
except Exception as e:
103
print 'Failed to delete', x
127
print ('Failed to delete', x)
106
130
icr = {icon_resources!r}
107
for context, name, size in icr:
133
def remove_icon(context, name, size, update=False):
108
134
cmd = ['xdg-icon-resource', 'uninstall', '--context', context, '--size', size, name]
109
if (context, name) != icr[-1]:
110
136
cmd.insert(2, '--noupdate')
111
ret = subprocess.call(cmd)
137
print ('Removing icon:', name, 'from context:', context, 'at size:', size)
138
ret = subprocess.call(cmd, shell=False)
113
print 'WARNING: Failed to remove icon', name
140
print ('WARNING: Failed to remove icon', name)
142
for i, (context, name, size) in enumerate(icr):
143
if context == 'mimetypes':
144
mimetype_icons.append((name, size))
146
remove_icon(context, name, size, update=i == len(icr) - 1)
115
148
mr = {menu_resources!r}
117
150
cmd = ['xdg-desktop-menu', 'uninstall', f]
118
ret = subprocess.call(cmd)
151
print ('Removing desktop file:', f)
152
ret = subprocess.call(cmd, shell=False)
120
print 'WARNING: Failed to remove menu item', f
122
os.remove(os.path.abspath(__file__))
154
print ('WARNING: Failed to remove menu item', f)
158
if mimetype_icons and raw_input('Remove the ebook format icons? [y/n]:').lower() in ['', 'y']:
159
for i, (name, size) in enumerate(mimetype_icons):
160
remove_icon('mimetypes', name, size, update=i == len(mimetype_icons) - 1)
430
469
os.path.join(self.opts.staging_root, 'etc')
432
471
scripts = cPickle.loads(P('scripts.pickle', data=True))
472
self.manifest = manifest or []
433
473
if getattr(sys, 'frozen_path', False):
434
self.info('Creating symlinks...')
435
for exe in scripts.keys():
436
dest = os.path.join(self.opts.staging_bindir, exe)
437
if os.path.lexists(dest):
439
tgt = os.path.join(getattr(sys, 'frozen_path'), exe)
440
self.info('\tSymlinking %s to %s'%(tgt, dest))
441
os.symlink(tgt, dest)
474
if os.access(self.opts.staging_bindir, os.W_OK):
475
self.info('Creating symlinks...')
476
for exe in scripts.keys():
477
dest = os.path.join(self.opts.staging_bindir, exe)
478
if os.path.lexists(dest):
480
tgt = os.path.join(getattr(sys, 'frozen_path'), exe)
481
self.info('\tSymlinking %s to %s'%(tgt, dest))
482
os.symlink(tgt, dest)
483
self.manifest.append(dest)
485
self.warning(textwrap.fill(
486
'No permission to write to %s, not creating program launch symlinks,'
487
' you should ensure that %s is in your PATH or create the symlinks yourself' % (
488
self.opts.staging_bindir, getattr(sys, 'frozen_path', 'the calibre installation directory'))))
444
manifest = [os.path.abspath(os.path.join(opts.staging_bindir, x)) for x in
446
self.manifest = manifest
447
490
self.icon_resources = []
448
491
self.menu_resources = []
449
492
self.mime_resources = []
493
self.appdata_resources = []
450
494
if islinux or isbsd:
451
495
self.setup_completion()
452
496
if islinux or isbsd:
465
509
os.rmdir(config_dir)
467
511
if warn is None and self.warnings:
468
self.info('There were %d warnings'%len(self.warnings))
512
self.info('\n\nThere were %d warnings\n'%len(self.warnings))
469
513
for args, kwargs in self.warnings:
470
514
self.info('*', *args, **kwargs)
473
517
def create_uninstaller(self):
474
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)
518
base = self.opts.staging_bindir
519
if not os.access(base, os.W_OK) and getattr(sys, 'frozen_path', False):
520
base = sys.frozen_path
521
dest = os.path.join(base, 'calibre-uninstall')
522
self.info('Creating un-installer:', dest)
523
raw = UNINSTALL.format(
524
python='/usr/bin/python', euid=os.geteuid(),
525
manifest=self.manifest, icon_resources=self.icon_resources,
526
mime_resources=self.mime_resources, menu_resources=self.menu_resources,
527
appdata_resources=self.appdata_resources, frozen_path=getattr(sys, 'frozen_path', None))
479
529
with open(dest, 'wb') as f:
499
549
from calibre.utils.smtp import option_parser as smtp_op
500
550
from calibre.library.server.main import option_parser as serv_op
501
551
from calibre.ebooks.oeb.polish.main import option_parser as polish_op, SUPPORTED
552
from calibre.ebooks.oeb.polish.import_book import IMPORTABLE
502
553
from calibre.debug import option_parser as debug_op
503
554
from calibre.ebooks import BOOK_EXTENSIONS
504
555
from calibre.customize.ui import available_input_formats
505
556
input_formats = sorted(all_input_formats())
506
tweak_formats = sorted(x.lower() for x in SUPPORTED)
557
tweak_formats = sorted(x.lower() for x in SUPPORTED|IMPORTABLE)
507
558
zsh = ZshCompleter(self.opts)
508
559
bc = os.path.join(os.path.dirname(self.opts.staging_sharedir),
509
560
'bash-completion')
516
567
f = os.path.join(self.opts.staging_etc, 'bash_completion.d/calibre')
517
568
if not os.path.exists(os.path.dirname(f)):
518
569
os.makedirs(os.path.dirname(f))
570
bash_comp_dest, zsh_comp_dest = f, None
520
572
self.info('Installing zsh completion to:', zsh.dest)
521
573
self.manifest.append(zsh.dest)
522
self.manifest.append(f)
574
zsh_comp_dest = zsh.dest
523
575
complete = 'calibre-complete'
524
576
if getattr(sys, 'frozen_path', None):
525
577
complete = os.path.join(getattr(sys, 'frozen_path'), complete)
677
733
self.icon_resources.append(('mimetypes', 'application-x-mobi8-ebook', '128'))
678
734
render_img('lt.png', 'calibre-gui.png', width=256, height=256)
679
735
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'))
736
self.icon_resources.append(('apps', 'calibre-gui', '256'))
737
render_img('viewer.png', 'calibre-viewer.png', width=256, height=256)
738
cc('xdg-icon-resource install --size 256 calibre-viewer.png calibre-viewer', shell=True)
739
self.icon_resources.append(('apps', 'calibre-viewer', '256'))
740
render_img('tweak.png', 'calibre-ebook-edit.png', width=256, height=256)
741
cc('xdg-icon-resource install --size 256 calibre-ebook-edit.png calibre-ebook-edit', shell=True)
742
self.icon_resources.append(('apps', 'calibre-ebook-edit', '256'))
688
744
mimetypes = set([])
689
745
for x in all_input_formats():
731
787
self.menu_resources.append(x)
732
788
ak = x.partition('.')[0]
733
789
if ak in APPDATA and os.access(appdata, os.W_OK):
734
write_appdata(ak, APPDATA[ak], appdata, translators)
790
self.appdata_resources.append(write_appdata(ak, APPDATA[ak], appdata, translators))
735
791
cc(['xdg-desktop-menu', 'forceupdate'])
736
f = open('calibre-mimetypes.xml', 'wb')
739
self.mime_resources.append('calibre-mimetypes.xml')
740
cc('xdg-mime install ./calibre-mimetypes.xml', shell=True)
792
MIME = P('calibre-mimetypes.xml')
793
self.mime_resources.append(MIME)
794
cc(['xdg-mime', 'install', MIME])
741
795
except Exception:
742
796
if self.opts.fatal_errors:
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"/>
982
<mime-type type="application/epub+zip">
983
<comment>EPUB ebook format</comment>
984
<glob pattern="*.epub"/>
986
<mime-type type="text/lrs">
987
<comment>SONY E-book source format</comment>
988
<glob pattern="*.lrs"/>
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"/>
995
<mime-type type="application/x-topaz-ebook">
996
<comment>Amazon Topaz ebook format</comment>
997
<glob pattern="*.tpz"/>
998
<glob pattern="*.azw1"/>
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"/>
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"/>
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"/>
1020
1029
def render_img(image, dest, width=128, height=128):
1021
1030
from PyQt4.Qt import QImage, Qt
1022
1031
img = QImage(I(image)).scaled(width, height, Qt.IgnoreAspectRatio, Qt.SmoothTransformation)