mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
New windows installer. If you are upgrading from a previous release, please uninstall calibre first
This commit is contained in:
parent
a9d86fd6c9
commit
78e0dfe1ed
BIN
icons/wix-banner.bmp
Normal file
BIN
icons/wix-banner.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
icons/wix-dialog.bmp
Normal file
BIN
icons/wix-dialog.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 152 KiB |
@ -19,7 +19,7 @@ __all__ = [
|
|||||||
'upload_user_manual', 'upload_installers', 'upload_demo',
|
'upload_user_manual', 'upload_installers', 'upload_demo',
|
||||||
'linux32', 'linux64', 'linux', 'linux_freeze',
|
'linux32', 'linux64', 'linux', 'linux_freeze',
|
||||||
'osx32_freeze', 'osx32', 'osx', 'rsync',
|
'osx32_freeze', 'osx32', 'osx', 'rsync',
|
||||||
'win32_freeze', 'win32', 'win', 'win2', 'win32_freeze2',
|
'win32_freeze', 'win32', 'win',
|
||||||
'stage1', 'stage2', 'stage3', 'publish'
|
'stage1', 'stage2', 'stage3', 'publish'
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -81,14 +81,11 @@ osx32 = OSX32()
|
|||||||
from setup.installer.osx.freeze import OSX32_Freeze
|
from setup.installer.osx.freeze import OSX32_Freeze
|
||||||
osx32_freeze = OSX32_Freeze()
|
osx32_freeze = OSX32_Freeze()
|
||||||
|
|
||||||
from setup.installer.windows import Win, Win32, Win2
|
from setup.installer.windows import Win, Win32
|
||||||
win = Win()
|
win = Win()
|
||||||
win32 = Win32()
|
win32 = Win32()
|
||||||
win2 = Win2()
|
|
||||||
from setup.installer.windows.freeze import Win32Freeze
|
from setup.installer.windows.freeze import Win32Freeze
|
||||||
win32_freeze = Win32Freeze()
|
win32_freeze = Win32Freeze()
|
||||||
from setup.installer.windows.freeze2 import Win32Freeze2
|
|
||||||
win32_freeze2 = Win32Freeze2()
|
|
||||||
|
|
||||||
from setup.pypi import PyPIRegister, PyPIUpload
|
from setup.pypi import PyPIRegister, PyPIUpload
|
||||||
pypi_register = PyPIRegister()
|
pypi_register = PyPIRegister()
|
||||||
|
@ -10,7 +10,6 @@ import os, shutil, subprocess
|
|||||||
|
|
||||||
from setup import Command, __appname__
|
from setup import Command, __appname__
|
||||||
from setup.installer import VMInstaller
|
from setup.installer import VMInstaller
|
||||||
from setup.installer.windows import build_installer
|
|
||||||
|
|
||||||
class Win(Command):
|
class Win(Command):
|
||||||
|
|
||||||
@ -30,32 +29,10 @@ class Win32(VMInstaller):
|
|||||||
VM_NAME = 'xp_build'
|
VM_NAME = 'xp_build'
|
||||||
VM = '/vmware/bin/%s'%VM_NAME
|
VM = '/vmware/bin/%s'%VM_NAME
|
||||||
FREEZE_COMMAND = 'win32_freeze'
|
FREEZE_COMMAND = 'win32_freeze'
|
||||||
SHUTDOWN_CMD = ['shutdown', '-s', '-t', '0', '-c',
|
|
||||||
'Shutdown called by calibre setup']
|
|
||||||
|
|
||||||
def download_installer(self):
|
|
||||||
installer = self.installer()
|
|
||||||
if os.path.exists('build/py2exe'):
|
|
||||||
shutil.rmtree('build/py2exe')
|
|
||||||
subprocess.check_call(('scp', '-rp', 'xp_build:build/%s/build/py2exe'%__appname__,
|
|
||||||
'build'))
|
|
||||||
if not os.path.exists('build/py2exe'):
|
|
||||||
self.warn('Failed to run py2exe')
|
|
||||||
raise SystemExit(1)
|
|
||||||
self.run_windows_install_jammer(installer)
|
|
||||||
|
|
||||||
def run_windows_install_jammer(self, installer):
|
|
||||||
build_installer.run_install_jammer(
|
|
||||||
installer_name=os.path.basename(installer))
|
|
||||||
if not os.path.exists(installer):
|
|
||||||
self.warn('Failed to run installjammer')
|
|
||||||
raise SystemExit(1)
|
|
||||||
|
|
||||||
class Win2(Win32):
|
|
||||||
|
|
||||||
FREEZE_COMMAND = 'win32_freeze2'
|
|
||||||
FREEZE_TEMPLATE = 'python -OO setup.py {freeze_command} --no-ice'
|
FREEZE_TEMPLATE = 'python -OO setup.py {freeze_command} --no-ice'
|
||||||
INSTALLER_EXT = 'msi'
|
INSTALLER_EXT = 'msi'
|
||||||
|
SHUTDOWN_CMD = ['shutdown.exe', '-s', '-c',
|
||||||
|
'Shutdown called by calibre setup']
|
||||||
|
|
||||||
def download_installer(self):
|
def download_installer(self):
|
||||||
installer = self.installer()
|
installer = self.installer()
|
||||||
@ -67,3 +44,4 @@ class Win2(Win32):
|
|||||||
self.warn('Failed to freeze')
|
self.warn('Failed to freeze')
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
import sys, time, subprocess, os, re
|
|
||||||
from setup import SRC, __appname__, __version__
|
|
||||||
|
|
||||||
INSTALLJAMMER = '/usr/local/installjammer/installjammer'
|
|
||||||
|
|
||||||
sv = re.sub(r'[a-z]\d+', '', __version__)
|
|
||||||
|
|
||||||
cmdline = [
|
|
||||||
INSTALLJAMMER,
|
|
||||||
'--build-dir', '/tmp/calibre-installjammer',
|
|
||||||
'-DAppName', __appname__,
|
|
||||||
'-DShortAppName', __appname__,
|
|
||||||
'-DApplicationURL', 'http://%s.kovidgoyal.net'%__appname__,
|
|
||||||
'-DCopyright', time.strftime('%Y Kovid Goyal'),
|
|
||||||
'-DPackageDescription', '%s is an e-book library manager. It can view, convert and catalog e-books in most of the major e-book formats. It can also talk to e-book reader devices. It can go out to the internet and fetch metadata for your books. It can download newspapers and convert them into e-books for convenient reading.'%__appname__,
|
|
||||||
'-DPackageSummary', '%s: E-book library management'%__appname__,
|
|
||||||
'-DVersion', __version__,
|
|
||||||
'-DInstallVersion', sv + '.0',
|
|
||||||
'-DLicense', open(os.path.join(os.path.dirname(SRC), 'LICENSE'), 'rb').read().replace('\n', '\r\n'),
|
|
||||||
'--output-dir', os.path.join(os.path.dirname(SRC), 'dist'),
|
|
||||||
'--platform', 'Windows',
|
|
||||||
'--verbose'
|
|
||||||
]
|
|
||||||
|
|
||||||
def run_install_jammer(installer_name='<%AppName%>-<%Version%><%Ext%>', build_for_release=True):
|
|
||||||
global cmdline
|
|
||||||
mpi = os.path.abspath(os.path.join(os.path.dirname(__file__), 'calibre', 'calibre.mpi'))
|
|
||||||
cmdline.extend(['-DWindows,Executable', installer_name])
|
|
||||||
compression = 'zlib'
|
|
||||||
if build_for_release:
|
|
||||||
cmdline += ['--build-for-release']
|
|
||||||
compression = 'lzma (solid)'
|
|
||||||
cmdline += ['-DCompressionMethod', compression]
|
|
||||||
cmdline += ['--build', mpi]
|
|
||||||
#print 'Running installjammer with cmdline:'
|
|
||||||
#print cmdline
|
|
||||||
subprocess.check_call(cmdline)
|
|
||||||
|
|
||||||
def main(args=sys.argv):
|
|
||||||
run_install_jammer(build_for_release=True)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(main())
|
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
<WixLocalization Culture="en-us" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
||||||
<String Id="AdvancedWelcomeEulaDlgDescriptionPerUser">Click Install to install the product with default options just for you. Click Advanced to change installation options. If you are upgrading from a {app} version older than 0.6.17, please uninstall {app} first.</String>
|
<String Id="AdvancedWelcomeEulaDlgDescriptionPerUser">If you are upgrading from a {app} version older than 0.6.17, please uninstall {app} first. Click Advanced to change installation settings.</String>
|
||||||
</WixLocalization>
|
</WixLocalization>
|
||||||
|
|
||||||
|
@ -1,193 +1,214 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
from __future__ import with_statement
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
'''
|
import sys, os, shutil, glob, py_compile, subprocess, re
|
||||||
Freeze app into executable using py2exe.
|
|
||||||
'''
|
from setup import Command, modules, functions, basenames, __version__, \
|
||||||
import sys, os
|
__appname__
|
||||||
|
from setup.build_environment import msvc, MT, RC
|
||||||
|
from setup.installer.windows.wix import WixMixIn
|
||||||
|
|
||||||
QT_DIR = 'C:\\Qt\\4.5.2'
|
QT_DIR = 'C:\\Qt\\4.5.2'
|
||||||
|
QT_DLLS = ['Core', 'Gui', 'Network', 'Svg', 'WebKit', 'Xml', 'phonon']
|
||||||
LIBUSB_DIR = 'C:\\libusb'
|
LIBUSB_DIR = 'C:\\libusb'
|
||||||
LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll'
|
LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll'
|
||||||
SW = r'C:\cygwin\home\kovid\sw'
|
SW = r'C:\cygwin\home\kovid\sw'
|
||||||
IMAGEMAGICK = os.path.join(SW, 'build', 'ImageMagick-6.5.6',
|
IMAGEMAGICK = os.path.join(SW, 'build', 'ImageMagick-6.5.6',
|
||||||
'VisualMagick', 'bin')
|
'VisualMagick', 'bin')
|
||||||
|
|
||||||
|
VERSION = re.sub('[a-z]\d+', '', __version__)
|
||||||
def fix_module_finder():
|
|
||||||
# ModuleFinder can't handle runtime changes to __path__, but win32com uses them
|
|
||||||
import py2exe.mf as modulefinder
|
|
||||||
import win32com
|
|
||||||
for p in win32com.__path__[1:]:
|
|
||||||
modulefinder.AddPackagePath("win32com", p)
|
|
||||||
for extra in ["win32com.shell"]: #,"win32com.mapi"
|
|
||||||
__import__(extra)
|
|
||||||
m = sys.modules[extra]
|
|
||||||
for p in m.__path__[1:]:
|
|
||||||
modulefinder.AddPackagePath(extra, p)
|
|
||||||
|
|
||||||
|
|
||||||
import os, shutil, zipfile, glob, re
|
|
||||||
from distutils.core import setup
|
|
||||||
from setup import __version__ as VERSION, __appname__ as APPNAME, scripts, \
|
|
||||||
basenames, SRC, Command
|
|
||||||
|
|
||||||
BASE_DIR = os.path.dirname(SRC)
|
|
||||||
ICONS = [os.path.abspath(os.path.join(BASE_DIR, 'icons', i)) for i in ('library.ico', 'viewer.ico')]
|
|
||||||
for icon in ICONS:
|
|
||||||
if not os.access(icon, os.R_OK):
|
|
||||||
raise Exception('No icon at '+icon)
|
|
||||||
|
|
||||||
VERSION = re.sub('[a-z]\d+', '', VERSION)
|
|
||||||
WINVER = VERSION+'.0'
|
WINVER = VERSION+'.0'
|
||||||
|
|
||||||
PY2EXE_DIR = os.path.join(BASE_DIR, 'build','py2exe')
|
DESCRIPTIONS = {
|
||||||
|
'calibre' : 'The main calibre program',
|
||||||
|
'ebook-viewer' : 'Viewer for all e-book formats',
|
||||||
|
'lrfviewer' : 'Viewer for LRF files',
|
||||||
|
'ebook-convert': 'Command line interface to the conversion/news download system',
|
||||||
|
'ebook-meta' : 'Command line interface for manipulating e-book metadata',
|
||||||
|
'calibredb' : 'Command line interface to the calibre database',
|
||||||
|
'calibre-launcher' : 'Utility functions common to all executables',
|
||||||
|
'calibre-debug' : 'Command line interface for calibre debugging/development',
|
||||||
|
'calibre-customize' : 'Command line interface to calibre plugin system',
|
||||||
|
'pdfmanipulate' : 'Command line tool to manipulate PDF files',
|
||||||
|
'calibre-server': 'Standalone calibre content server',
|
||||||
|
'calibre-parallel': 'calibre worker process',
|
||||||
|
'calibre-smtp' : 'Command line interface for sending books via email',
|
||||||
|
}
|
||||||
|
|
||||||
info = warn = None
|
class Win32Freeze(Command, WixMixIn):
|
||||||
|
|
||||||
class Win32Freeze(Command):
|
description = 'Free windows calibre installation'
|
||||||
|
|
||||||
description = 'Freeze windows calibre installation'
|
def add_options(self, parser):
|
||||||
|
parser.add_option('--no-ice', default=False, action='store_true',
|
||||||
|
help='Disable ICE checks when building MSI (needed when running'
|
||||||
|
' from cygwin sshd)')
|
||||||
|
parser.add_option('--msi-compression', '--compress', default='high',
|
||||||
|
help='Compression when generating installer. Set to none to disable')
|
||||||
|
parser.add_option('--keep-site', default=False, action='store_true',
|
||||||
|
help='Keep human readable site.py')
|
||||||
|
parser.add_option('--verbose', default=0, action="count",
|
||||||
|
help="Be more verbose")
|
||||||
|
|
||||||
def run(self, opts):
|
def run(self, opts):
|
||||||
global info, warn
|
self.SW = SW
|
||||||
info, warn = self.info, self.warn
|
self.opts = opts
|
||||||
main()
|
self.src_root = self.d(self.SRC)
|
||||||
|
self.base = self.j(self.d(self.SRC), 'build', 'winfrozen')
|
||||||
|
self.rc_template = self.j(self.d(self.a(__file__)), 'template.rc')
|
||||||
|
self.py_ver = ''.join(map(str, sys.version_info[:2]))
|
||||||
|
self.lib_dir = self.j(self.base, 'Lib')
|
||||||
|
|
||||||
BOOT_COMMON = '''\
|
self.initbase()
|
||||||
import sys, os
|
self.build_launchers()
|
||||||
if sys.frozen == "windows_exe":
|
self.freeze()
|
||||||
class Stderr(object):
|
self.embed_manifests()
|
||||||
softspace = 0
|
self.install_site_py()
|
||||||
_file = None
|
self.create_installer()
|
||||||
_error = None
|
|
||||||
def write(self, text, alert=sys._MessageBox, fname=os.path.expanduser('~\calibre.log')):
|
|
||||||
if self._file is None and self._error is None:
|
|
||||||
try:
|
|
||||||
self._file = open(fname, 'wb')
|
|
||||||
except Exception, details:
|
|
||||||
self._error = details
|
|
||||||
import atexit
|
|
||||||
atexit.register(alert, 0,
|
|
||||||
("The logfile %s could not be opened: "
|
|
||||||
"\\n%s\\n\\nTry setting the HOME environment "
|
|
||||||
"variable to a directory for which you "
|
|
||||||
"have write permission.") % (fname, details),
|
|
||||||
"Errors occurred")
|
|
||||||
else:
|
|
||||||
import atexit
|
|
||||||
#atexit.register(alert, 0,
|
|
||||||
# "See the logfile '%s' for details" % fname,
|
|
||||||
# "Errors occurred")
|
|
||||||
if self._file is not None:
|
|
||||||
self._file.write(text)
|
|
||||||
self._file.flush()
|
|
||||||
def flush(self):
|
|
||||||
if self._file is not None:
|
|
||||||
self._file.flush()
|
|
||||||
|
|
||||||
#del sys._MessageBox
|
def initbase(self):
|
||||||
#del Stderr
|
if self.e(self.base):
|
||||||
|
shutil.rmtree(self.base)
|
||||||
|
os.makedirs(self.base)
|
||||||
|
|
||||||
class Blackhole(object):
|
def freeze(self):
|
||||||
softspace = 0
|
shutil.copy2(self.j(self.src_root, 'LICENSE'), self.base)
|
||||||
def write(self, text):
|
|
||||||
pass
|
|
||||||
def flush(self):
|
|
||||||
pass
|
|
||||||
sys.stdout = Stderr()
|
|
||||||
sys.stderr = Stderr()
|
|
||||||
del Blackhole
|
|
||||||
|
|
||||||
# Disable linecache.getline() which is called by
|
self.info('Adding plugins...')
|
||||||
# traceback.extract_stack() when an exception occurs to try and read
|
tgt = os.path.join(self.base, 'plugins')
|
||||||
# the filenames embedded in the packaged python code. This is really
|
|
||||||
# annoying on windows when the d: or e: on our build box refers to
|
|
||||||
# someone elses removable or network drive so the getline() call
|
|
||||||
# causes it to ask them to insert a disk in that drive.
|
|
||||||
import linecache
|
|
||||||
def fake_getline(filename, lineno, module_globals=None):
|
|
||||||
return ''
|
|
||||||
linecache.orig_getline = linecache.getline
|
|
||||||
linecache.getline = fake_getline
|
|
||||||
|
|
||||||
del linecache, fake_getline
|
|
||||||
|
|
||||||
fenc = sys.getfilesystemencoding( )
|
|
||||||
base = os.path.dirname(sys.executable.decode(fenc))
|
|
||||||
sys.resources_location = os.path.join(base, 'resources')
|
|
||||||
sys.extensions_location = os.path.join(base, 'plugins')
|
|
||||||
|
|
||||||
dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
|
|
||||||
if dv and os.path.exists(dv):
|
|
||||||
sys.path.insert(0, os.path.abspath(dv))
|
|
||||||
|
|
||||||
del sys
|
|
||||||
'''
|
|
||||||
|
|
||||||
try:
|
|
||||||
import py2exe
|
|
||||||
bc = py2exe.build_exe.py2exe
|
|
||||||
except ImportError:
|
|
||||||
py2exe = object
|
|
||||||
bc = object
|
|
||||||
|
|
||||||
class BuildEXE(bc):
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
py2exe.build_exe.py2exe.run(self)
|
|
||||||
info('\nAdding plugins...')
|
|
||||||
tgt = os.path.join(self.dist_dir, 'plugins')
|
|
||||||
if not os.path.exists(tgt):
|
if not os.path.exists(tgt):
|
||||||
os.mkdir(tgt)
|
os.mkdir(tgt)
|
||||||
for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.dll')):
|
base = self.j(self.SRC, 'calibre', 'plugins')
|
||||||
shutil.copyfile(f, os.path.join(self.dist_dir, os.path.basename(f)))
|
for pat in ('*.pyd', '*.manifest'):
|
||||||
for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.pyd')):
|
for f in glob.glob(self.j(base, pat)):
|
||||||
shutil.copyfile(f, os.path.join(tgt, os.path.basename(f)))
|
shutil.copy2(f, tgt)
|
||||||
for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.manifest')):
|
|
||||||
shutil.copyfile(f, os.path.join(tgt, os.path.basename(f)))
|
|
||||||
shutil.copyfile('LICENSE', os.path.join(self.dist_dir, 'LICENSE'))
|
|
||||||
|
|
||||||
|
self.info('Adding resources...')
|
||||||
info('\nAdding resources...')
|
tgt = self.j(self.base, 'resources')
|
||||||
tgt = os.path.join(self.dist_dir, 'resources')
|
|
||||||
if os.path.exists(tgt):
|
if os.path.exists(tgt):
|
||||||
shutil.rmtree(tgt)
|
shutil.rmtree(tgt)
|
||||||
shutil.copytree(os.path.join(BASE_DIR, 'resources'), tgt)
|
shutil.copytree(self.j(self.src_root, 'resources'), tgt)
|
||||||
|
|
||||||
info('\nAdding QtXml4.dll')
|
self.info('Adding Qt and python...')
|
||||||
shutil.copyfile(os.path.join(QT_DIR, 'bin', 'QtXml4.dll'),
|
self.dll_dir = self.j(self.base, 'DLLs')
|
||||||
os.path.join(self.dist_dir, 'QtXml4.dll'))
|
shutil.copytree(r'C:\Python%s\DLLs'%self.py_ver, self.dll_dir,
|
||||||
info('\nAdding Qt plugins...')
|
ignore=shutil.ignore_patterns('msvc*.dll', 'Microsoft.*'))
|
||||||
|
for x in QT_DLLS:
|
||||||
|
x += '4.dll'
|
||||||
|
if not x.startswith('phonon'): x = 'Qt'+x
|
||||||
|
shutil.copy2(os.path.join(QT_DIR, 'bin', x), self.dll_dir)
|
||||||
|
shutil.copy2(r'C:\windows\system32\python%s.dll'%self.py_ver,
|
||||||
|
self.dll_dir)
|
||||||
|
for x in os.walk(r'C:\Python%s\Lib'%self.py_ver):
|
||||||
|
for f in x[-1]:
|
||||||
|
if f.lower().endswith('.dll'):
|
||||||
|
f = self.j(x[0], f)
|
||||||
|
if 'py2exe' not in f:
|
||||||
|
shutil.copy2(f, self.dll_dir)
|
||||||
|
shutil.copy2(
|
||||||
|
r'C:\Python%(v)s\Lib\site-packages\pywin32_system32\pywintypes%(v)s.dll'
|
||||||
|
% dict(v=self.py_ver), self.dll_dir)
|
||||||
|
|
||||||
|
def ignore_lib(root, items):
|
||||||
|
ans = []
|
||||||
|
for x in items:
|
||||||
|
ext = os.path.splitext(x)[1]
|
||||||
|
if (not ext and (x in ('demos', 'tests') or 'py2exe' in x)) or \
|
||||||
|
(ext in ('.dll', '.chm', '.htm', '.txt')):
|
||||||
|
ans.append(x)
|
||||||
|
return ans
|
||||||
|
|
||||||
|
shutil.copytree(r'C:\Python%s\Lib'%self.py_ver, self.lib_dir,
|
||||||
|
ignore=ignore_lib)
|
||||||
|
|
||||||
|
# Fix win32com
|
||||||
|
sp_dir = self.j(self.lib_dir, 'site-packages')
|
||||||
|
comext = self.j(sp_dir, 'win32comext')
|
||||||
|
shutil.copytree(self.j(comext, 'shell'), self.j(sp_dir, 'win32com', 'shell'))
|
||||||
|
shutil.rmtree(comext)
|
||||||
|
|
||||||
|
for pat in (r'numpy', r'PyQt4\uic\port_v3'):
|
||||||
|
x = glob.glob(self.j(self.lib_dir, 'site-packages', pat))[0]
|
||||||
|
shutil.rmtree(x)
|
||||||
|
|
||||||
|
self.info('Adding calibre sources...')
|
||||||
|
for x in glob.glob(self.j(self.SRC, '*')):
|
||||||
|
shutil.copytree(x, self.j(sp_dir, self.b(x)))
|
||||||
|
|
||||||
|
for x in (r'calibre\manual', r'calibre\trac', 'pythonwin'):
|
||||||
|
shutil.rmtree(self.j(sp_dir, x))
|
||||||
|
|
||||||
|
for x in os.walk(self.j(sp_dir, 'calibre')):
|
||||||
|
for f in x[-1]:
|
||||||
|
if not f.endswith('.py'):
|
||||||
|
os.remove(self.j(x[0], f))
|
||||||
|
|
||||||
|
self.info('Byte-compiling all python modules...')
|
||||||
|
for x in ('test', 'lib2to3', 'distutils'):
|
||||||
|
shutil.rmtree(self.j(self.lib_dir, x))
|
||||||
|
for x in os.walk(self.lib_dir):
|
||||||
|
root = x[0]
|
||||||
|
for f in x[-1]:
|
||||||
|
if f.endswith('.py'):
|
||||||
|
y = self.j(root, f)
|
||||||
|
rel = os.path.relpath(y, self.lib_dir)
|
||||||
|
try:
|
||||||
|
py_compile.compile(y, dfile=rel, doraise=True)
|
||||||
|
os.remove(y)
|
||||||
|
except:
|
||||||
|
self.warn('Failed to byte-compile', y)
|
||||||
|
pyc, pyo = y+'c', y+'o'
|
||||||
|
epyc, epyo, epy = map(os.path.exists, (pyc,pyo,y))
|
||||||
|
if (epyc or epyo) and epy:
|
||||||
|
os.remove(y)
|
||||||
|
if epyo and epyc:
|
||||||
|
os.remove(pyc)
|
||||||
|
|
||||||
|
self.info('\nAdding Qt plugins...')
|
||||||
qt_prefix = QT_DIR
|
qt_prefix = QT_DIR
|
||||||
plugdir = os.path.join(qt_prefix, 'plugins')
|
plugdir = self.j(qt_prefix, 'plugins')
|
||||||
|
tdir = self.j(self.base, 'qt_plugins')
|
||||||
for d in ('imageformats', 'codecs', 'iconengines'):
|
for d in ('imageformats', 'codecs', 'iconengines'):
|
||||||
info(d)
|
self.info('\t', d)
|
||||||
imfd = os.path.join(plugdir, d)
|
imfd = os.path.join(plugdir, d)
|
||||||
tg = os.path.join(self.dist_dir, d)
|
tg = os.path.join(tdir, d)
|
||||||
if os.path.exists(tg):
|
if os.path.exists(tg):
|
||||||
shutil.rmtree(tg)
|
shutil.rmtree(tg)
|
||||||
shutil.copytree(imfd, tg)
|
shutil.copytree(imfd, tg)
|
||||||
|
|
||||||
info('Adding main scripts')
|
|
||||||
f = zipfile.ZipFile(os.path.join(PY2EXE_DIR, 'library.zip'), 'a', zipfile.ZIP_DEFLATED)
|
|
||||||
for i in scripts['console'] + scripts['gui']:
|
|
||||||
f.write(i, i.partition('\\')[-1])
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
info('Copying icons')
|
|
||||||
for icon in ICONS:
|
|
||||||
shutil.copyfile(icon, os.path.join(PY2EXE_DIR, os.path.basename(icon)))
|
|
||||||
|
|
||||||
print
|
print
|
||||||
print 'Adding third party dependencies'
|
print 'Adding third party dependencies'
|
||||||
tdir = os.path.join(PY2EXE_DIR, 'driver')
|
tdir = os.path.join(self.base, 'driver')
|
||||||
os.makedirs(tdir)
|
os.makedirs(tdir)
|
||||||
for pat in ('*.dll', '*.sys', '*.cat', '*.inf'):
|
for pat in ('*.dll', '*.sys', '*.cat', '*.inf'):
|
||||||
for f in glob.glob(os.path.join(LIBUSB_DIR, pat)):
|
for f in glob.glob(os.path.join(LIBUSB_DIR, pat)):
|
||||||
shutil.copyfile(f, os.path.join(tdir, os.path.basename(f)))
|
shutil.copyfile(f, os.path.join(tdir, os.path.basename(f)))
|
||||||
|
print '\tAdding unrar'
|
||||||
|
shutil.copyfile(LIBUNRAR,
|
||||||
|
os.path.join(self.dll_dir, os.path.basename(LIBUNRAR)))
|
||||||
|
|
||||||
|
print '\tAdding misc binary deps'
|
||||||
|
bindir = os.path.join(SW, 'bin')
|
||||||
|
shutil.copy2(os.path.join(bindir, 'pdftohtml.exe'), self.base)
|
||||||
|
for pat in ('*.dll',):
|
||||||
|
for f in glob.glob(os.path.join(bindir, pat)):
|
||||||
|
ok = True
|
||||||
|
for ex in ('expatw',):
|
||||||
|
if ex in f.lower():
|
||||||
|
ok = False
|
||||||
|
if not ok: continue
|
||||||
|
dest = self.dll_dir
|
||||||
|
shutil.copy2(f, dest)
|
||||||
|
for x in ('zlib1.dll', 'libxml2.dll'):
|
||||||
|
shutil.copy2(self.j(bindir, x+'.manifest'), self.dll_dir)
|
||||||
|
|
||||||
|
shutil.copytree(os.path.join(SW, 'etc', 'fonts'),
|
||||||
|
os.path.join(self.base, 'fontconfig'))
|
||||||
# Copy ImageMagick
|
# Copy ImageMagick
|
||||||
for pat in ('*.dll', '*.xml'):
|
for pat in ('*.dll', '*.xml'):
|
||||||
for f in glob.glob(self.j(IMAGEMAGICK, pat)):
|
for f in glob.glob(self.j(IMAGEMAGICK, pat)):
|
||||||
@ -197,95 +218,142 @@ class BuildEXE(bc):
|
|||||||
if not ok: continue
|
if not ok: continue
|
||||||
shutil.copy2(f, self.dll_dir)
|
shutil.copy2(f, self.dll_dir)
|
||||||
|
|
||||||
print '\tAdding unrar'
|
def embed_manifests(self):
|
||||||
shutil.copyfile(LIBUNRAR, os.path.join(PY2EXE_DIR, os.path.basename(LIBUNRAR)))
|
self.info('Embedding remaining manifests...')
|
||||||
|
for x in os.walk(self.base):
|
||||||
|
for f in x[-1]:
|
||||||
|
base, ext = os.path.splitext(f)
|
||||||
|
if ext != '.manifest': continue
|
||||||
|
dll = self.j(x[0], base)
|
||||||
|
manifest = self.j(x[0], f)
|
||||||
|
res = 2
|
||||||
|
if os.path.splitext(dll)[1] == '.exe':
|
||||||
|
res = 1
|
||||||
|
if os.path.exists(dll):
|
||||||
|
self.run_builder([MT, '-manifest', manifest,
|
||||||
|
'-outputresource:%s;%d'%(dll,res)])
|
||||||
|
os.remove(manifest)
|
||||||
|
|
||||||
print '\tAdding misc binary deps'
|
def compress(self):
|
||||||
bindir = os.path.join(SW, 'bin')
|
self.info('Compressing app dir using 7-zip')
|
||||||
shutil.copy2(os.path.join(bindir, 'pdftohtml.exe'), PY2EXE_DIR)
|
subprocess.check_call([r'C:\Program Files\7-Zip\7z.exe', 'a', '-r',
|
||||||
for pat in ('*.dll', '*.xml'):
|
'-scsUTF-8', '-sfx', 'winfrozen', 'winfrozen'], cwd=self.base)
|
||||||
for f in glob.glob(os.path.join(bindir, pat)):
|
|
||||||
shutil.copy2(f, PY2EXE_DIR)
|
|
||||||
for x in ('Microsoft.VC90.CRT', 'zlib1.dll', 'libxml2.dll'):
|
|
||||||
shutil.copy2(os.path.join(bindir, x+'.manifest'), PY2EXE_DIR)
|
|
||||||
shutil.copytree(os.path.join(SW, 'etc', 'fonts'),
|
|
||||||
os.path.join(PY2EXE_DIR, 'fontconfig'))
|
|
||||||
|
|
||||||
print
|
|
||||||
print 'Doing DLL redirection' # See http://msdn.microsoft.com/en-us/library/ms682600(VS.85).aspx
|
|
||||||
for f in glob.glob(os.path.join(PY2EXE_DIR, '*.exe')):
|
|
||||||
open(f + '.local', 'w').write('\n')
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def exe_factory(dest_base, script, icon_resources=None):
|
|
||||||
exe = {
|
|
||||||
'dest_base' : dest_base,
|
|
||||||
'script' : script,
|
|
||||||
'name' : dest_base,
|
|
||||||
'version' : WINVER,
|
|
||||||
'description' : 'calibre - E-book library management',
|
|
||||||
'author' : 'Kovid Goyal',
|
|
||||||
'copyright' : '(c) Kovid Goyal, 2008',
|
|
||||||
'company' : 'kovidgoyal.net',
|
|
||||||
}
|
|
||||||
if icon_resources is not None:
|
|
||||||
exe['icon_resources'] = icon_resources
|
|
||||||
return exe
|
|
||||||
|
|
||||||
def main(args=sys.argv):
|
|
||||||
sys.argv[1:2] = ['py2exe']
|
|
||||||
if os.path.exists(PY2EXE_DIR):
|
|
||||||
shutil.rmtree(PY2EXE_DIR)
|
|
||||||
|
|
||||||
fix_module_finder()
|
|
||||||
|
|
||||||
boot_common = os.path.join(sys.prefix, 'Lib', 'site-packages', 'py2exe',
|
|
||||||
'boot_common.py')
|
|
||||||
open(boot_common, 'wb').write(BOOT_COMMON)
|
|
||||||
|
|
||||||
console = [exe_factory(basenames['console'][i], scripts['console'][i])
|
|
||||||
for i in range(len(scripts['console']))]
|
|
||||||
setup(
|
|
||||||
cmdclass = {'py2exe': BuildEXE},
|
|
||||||
windows = [
|
|
||||||
exe_factory(APPNAME, scripts['gui'][0], [(1, ICONS[0])]),
|
|
||||||
exe_factory('lrfviewer', scripts['gui'][1], [(1, ICONS[1])]),
|
|
||||||
exe_factory('ebook-viewer', scripts['gui'][2], [(1, ICONS[1])]),
|
|
||||||
],
|
|
||||||
console = console,
|
|
||||||
options = { 'py2exe' : {'compressed': 1,
|
|
||||||
'optimize' : 2,
|
|
||||||
'dist_dir' : PY2EXE_DIR,
|
|
||||||
'includes' : [
|
|
||||||
'sip', 'pkg_resources', 'PyQt4.QtSvg',
|
|
||||||
'mechanize', 'ClientForm', 'wmi',
|
|
||||||
'win32file', 'pythoncom',
|
|
||||||
'email.iterators',
|
|
||||||
'email.generator',
|
|
||||||
'win32process', 'win32api', 'msvcrt',
|
|
||||||
'win32event',
|
|
||||||
'sqlite3.dump',
|
|
||||||
'BeautifulSoup', 'pyreadline',
|
|
||||||
'pydoc', 'IPython.Extensions.*',
|
|
||||||
'calibre.web.feeds.recipes.*',
|
|
||||||
'calibre.gui2.convert.*',
|
|
||||||
'PyQt4.QtWebKit', 'PyQt4.QtNetwork',
|
|
||||||
],
|
|
||||||
'packages' : ['PIL', 'lxml', 'cherrypy',
|
|
||||||
'dateutil', 'dns'],
|
|
||||||
'excludes' : ["Tkconstants", "Tkinter", "tcl",
|
|
||||||
"_imagingtk", "ImageTk",
|
|
||||||
"FixTk",
|
|
||||||
'PyQt4.uic.port_v3.proxy_base'
|
|
||||||
],
|
|
||||||
'dll_excludes' : ['mswsock.dll', 'tcl85.dll',
|
|
||||||
'tk85.dll'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
|
def embed_resources(self, module, desc=None):
|
||||||
|
icon_base = self.j(self.src_root, 'icons')
|
||||||
|
icon_map = {'calibre':'library', 'ebook-viewer':'viewer',
|
||||||
|
'lrfviewer':'viewer'}
|
||||||
|
file_type = 'DLL' if module.endswith('.dll') else 'APP'
|
||||||
|
template = open(self.rc_template, 'rb').read()
|
||||||
|
bname = self.b(module)
|
||||||
|
internal_name = os.path.splitext(bname)[0]
|
||||||
|
icon = icon_map.get(internal_name, 'command-prompt')
|
||||||
|
icon = self.j(icon_base, icon+'.ico')
|
||||||
|
if desc is None:
|
||||||
|
defdesc = 'A dynamic link library' if file_type == 'DLL' else \
|
||||||
|
'An executable program'
|
||||||
|
desc = DESCRIPTIONS.get(internal_name, defdesc)
|
||||||
|
license = 'GNU GPL v3.0'
|
||||||
|
def e(val): return val.replace('"', r'\"')
|
||||||
|
rc = template.format(
|
||||||
|
icon=icon,
|
||||||
|
file_type=e(file_type),
|
||||||
|
file_version=e(WINVER.replace('.', ',')),
|
||||||
|
file_version_str=e(WINVER),
|
||||||
|
file_description=e(desc),
|
||||||
|
internal_name=e(internal_name),
|
||||||
|
original_filename=e(bname),
|
||||||
|
product_version=e(WINVER.replace('.', ',')),
|
||||||
|
product_version_str=e(__version__),
|
||||||
|
product_name=e(__appname__),
|
||||||
|
product_description=e(__appname__+' - E-book management'),
|
||||||
|
legal_copyright=e(license),
|
||||||
|
legal_trademarks=e(__appname__ + \
|
||||||
|
' is a registered U.S. trademark number 3,666,525')
|
||||||
)
|
)
|
||||||
return 0
|
tdir = self.obj_dir
|
||||||
|
rcf = self.j(tdir, bname+'.rc')
|
||||||
|
with open(rcf, 'wb') as f:
|
||||||
|
f.write(rc)
|
||||||
|
res = self.j(tdir, bname + '.res')
|
||||||
|
cmd = [RC, '/n', '/fo'+res, rcf]
|
||||||
|
self.run_builder(cmd)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def install_site_py(self):
|
||||||
|
if not os.path.exists(self.lib_dir):
|
||||||
|
os.makedirs(self.lib_dir)
|
||||||
|
shutil.copy2(self.j(self.d(__file__), 'site.py'), self.lib_dir)
|
||||||
|
y = os.path.join(self.lib_dir, 'site.py')
|
||||||
|
py_compile.compile(y, dfile='site.py', doraise=True)
|
||||||
|
if not self.opts.keep_site:
|
||||||
|
os.remove(y)
|
||||||
|
|
||||||
|
def run_builder(self, cmd):
|
||||||
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
if p.wait() != 0:
|
||||||
|
self.info('Failed to run builder:')
|
||||||
|
self.info(*cmd)
|
||||||
|
self.info(p.stdout.read())
|
||||||
|
self.info(p.stderr.read())
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def build_launchers(self):
|
||||||
|
self.obj_dir = self.j(self.src_root, 'build', 'launcher')
|
||||||
|
if not os.path.exists(self.obj_dir):
|
||||||
|
os.makedirs(self.obj_dir)
|
||||||
|
base = self.j(self.src_root, 'setup', 'installer', 'windows')
|
||||||
|
sources = [self.j(base, x) for x in ['util.c']]
|
||||||
|
headers = [self.j(base, x) for x in ['util.h']]
|
||||||
|
objects = [self.j(self.obj_dir, self.b(x)+'.obj') for x in sources]
|
||||||
|
cflags = '/c /EHsc /MD /W3 /Ox /nologo /D_UNICODE'.split()
|
||||||
|
cflags += ['/DPYDLL="python%s.dll"'%self.py_ver, '/IC:/Python%s/include'%self.py_ver]
|
||||||
|
for src, obj in zip(sources, objects):
|
||||||
|
if not self.newer(obj, headers+[src]): continue
|
||||||
|
cmd = [msvc.cc] + cflags + ['/Fo'+obj, '/Tc'+src]
|
||||||
|
self.run_builder(cmd)
|
||||||
|
|
||||||
|
dll = self.j(self.obj_dir, 'calibre-launcher.dll')
|
||||||
|
ver = '.'.join(__version__.split('.')[:2])
|
||||||
|
if self.newer(dll, objects):
|
||||||
|
cmd = [msvc.linker, '/DLL', '/INCREMENTAL:NO', '/VERSION:'+ver,
|
||||||
|
'/OUT:'+dll, '/nologo', '/MACHINE:X86'] + objects + \
|
||||||
|
[self.embed_resources(dll),
|
||||||
|
'/LIBPATH:C:/Python%s/libs'%self.py_ver,
|
||||||
|
'python%s.lib'%self.py_ver,
|
||||||
|
'/delayload:python%s.dll'%self.py_ver]
|
||||||
|
self.info('Linking calibre-launcher.dll')
|
||||||
|
self.run_builder(cmd)
|
||||||
|
|
||||||
|
src = self.j(base, 'main.c')
|
||||||
|
shutil.copy2(dll, self.base)
|
||||||
|
for typ in ('console', 'gui', ):
|
||||||
|
self.info('Processing %s launchers'%typ)
|
||||||
|
subsys = 'WINDOWS' if typ == 'gui' else 'CONSOLE'
|
||||||
|
for mod, bname, func in zip(modules[typ], basenames[typ],
|
||||||
|
functions[typ]):
|
||||||
|
xflags = list(cflags)
|
||||||
|
if typ == 'gui':
|
||||||
|
xflags += ['/DGUI_APP=']
|
||||||
|
|
||||||
|
xflags += ['/DMODULE="%s"'%mod, '/DBASENAME="%s"'%bname,
|
||||||
|
'/DFUNCTION="%s"'%func]
|
||||||
|
dest = self.j(self.obj_dir, bname+'.obj')
|
||||||
|
if self.newer(dest, [src]+headers):
|
||||||
|
self.info('Compiling', bname)
|
||||||
|
cmd = [msvc.cc] + xflags + ['/Tc'+src, '/Fo'+dest]
|
||||||
|
self.run_builder(cmd)
|
||||||
|
exe = self.j(self.base, bname+'.exe')
|
||||||
|
manifest = exe+'.manifest'
|
||||||
|
lib = dll.replace('.dll', '.lib')
|
||||||
|
if self.newer(exe, [dest, lib, self.rc_template, __file__]):
|
||||||
|
self.info('Linking', bname)
|
||||||
|
cmd = [msvc.linker] + ['/INCREMENTAL:NO', '/MACHINE:X86',
|
||||||
|
'/LIBPATH:'+self.obj_dir, '/SUBSYSTEM:'+subsys,
|
||||||
|
'/LIBPATH:C:/Python%s/libs'%self.py_ver, '/RELEASE',
|
||||||
|
'/OUT:'+exe, self.embed_resources(exe),
|
||||||
|
dest, lib]
|
||||||
|
self.run_builder(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,358 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
|
||||||
from __future__ import with_statement
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import sys, os, shutil, glob, py_compile, subprocess, re
|
|
||||||
|
|
||||||
from setup import Command, modules, functions, basenames, __version__, \
|
|
||||||
__appname__
|
|
||||||
from setup.build_environment import msvc, MT, RC
|
|
||||||
from setup.installer.windows.wix import WixMixIn
|
|
||||||
|
|
||||||
QT_DIR = 'C:\\Qt\\4.5.2'
|
|
||||||
QT_DLLS = ['Core', 'Gui', 'Network', 'Svg', 'WebKit', 'Xml', 'phonon']
|
|
||||||
LIBUSB_DIR = 'C:\\libusb'
|
|
||||||
LIBUNRAR = 'C:\\Program Files\\UnrarDLL\\unrar.dll'
|
|
||||||
SW = r'C:\cygwin\home\kovid\sw'
|
|
||||||
IMAGEMAGICK = os.path.join(SW, 'build', 'ImageMagick-6.5.6',
|
|
||||||
'VisualMagick', 'bin')
|
|
||||||
|
|
||||||
VERSION = re.sub('[a-z]\d+', '', __version__)
|
|
||||||
WINVER = VERSION+'.0'
|
|
||||||
|
|
||||||
DESCRIPTIONS = {
|
|
||||||
'calibre' : 'The main calibre program',
|
|
||||||
'ebook-viewer' : 'Viewer for all e-book formats',
|
|
||||||
'lrfviewer' : 'Viewer for LRF files',
|
|
||||||
'ebook-convert': 'Command line interface to the conversion/news download system',
|
|
||||||
'ebook-meta' : 'Command line interface for manipulating e-book metadata',
|
|
||||||
'calibredb' : 'Command line interface to the calibre database',
|
|
||||||
'calibre-launcher' : 'Utility functions common to all executables',
|
|
||||||
'calibre-debug' : 'Command line interface for calibre debugging/development',
|
|
||||||
'calibre-customize' : 'Command line interface to calibre plugin system',
|
|
||||||
'pdfmanipulate' : 'Command line tool to manipulate PDF files',
|
|
||||||
'calibre-server': 'Standalone calibre content server',
|
|
||||||
'calibre-parallel': 'calibre worker process',
|
|
||||||
'calibre-smtp' : 'Command line interface for sending books via email',
|
|
||||||
}
|
|
||||||
|
|
||||||
class Win32Freeze2(Command, WixMixIn):
|
|
||||||
|
|
||||||
description = 'Free windows calibre installation'
|
|
||||||
|
|
||||||
def add_options(self, parser):
|
|
||||||
parser.add_option('--no-ice', default=False, action='store_true',
|
|
||||||
help='Disable ICE checks when building MSI (needed when running'
|
|
||||||
' from cygwin sshd)')
|
|
||||||
parser.add_option('--msi-compression', '--compress', default='high',
|
|
||||||
help='Compression when generating installer. Set to none to disable')
|
|
||||||
parser.add_option('--verbose', default=0, action="count",
|
|
||||||
help="Be moer verbose")
|
|
||||||
|
|
||||||
def run(self, opts):
|
|
||||||
self.opts = opts
|
|
||||||
self.src_root = self.d(self.SRC)
|
|
||||||
self.base = self.j(self.d(self.SRC), 'build', 'winfrozen')
|
|
||||||
self.rc_template = self.j(self.d(self.a(__file__)), 'template.rc')
|
|
||||||
self.py_ver = ''.join(map(str, sys.version_info[:2]))
|
|
||||||
self.lib_dir = self.j(self.base, 'Lib')
|
|
||||||
|
|
||||||
self.initbase()
|
|
||||||
self.build_launchers()
|
|
||||||
self.freeze()
|
|
||||||
self.embed_manifests()
|
|
||||||
self.install_site_py()
|
|
||||||
self.create_installer()
|
|
||||||
|
|
||||||
def initbase(self):
|
|
||||||
if self.e(self.base):
|
|
||||||
shutil.rmtree(self.base)
|
|
||||||
os.makedirs(self.base)
|
|
||||||
|
|
||||||
def freeze(self):
|
|
||||||
shutil.copy2(self.j(self.src_root, 'LICENSE'), self.base)
|
|
||||||
|
|
||||||
self.info('Adding plugins...')
|
|
||||||
tgt = os.path.join(self.base, 'plugins')
|
|
||||||
if not os.path.exists(tgt):
|
|
||||||
os.mkdir(tgt)
|
|
||||||
base = self.j(self.SRC, 'calibre', 'plugins')
|
|
||||||
for pat in ('*.pyd', '*.manifest'):
|
|
||||||
for f in glob.glob(self.j(base, pat)):
|
|
||||||
shutil.copy2(f, tgt)
|
|
||||||
|
|
||||||
self.info('Adding resources...')
|
|
||||||
tgt = self.j(self.base, 'resources')
|
|
||||||
if os.path.exists(tgt):
|
|
||||||
shutil.rmtree(tgt)
|
|
||||||
shutil.copytree(self.j(self.src_root, 'resources'), tgt)
|
|
||||||
|
|
||||||
self.info('Adding Qt and python...')
|
|
||||||
self.dll_dir = self.j(self.base, 'DLLs')
|
|
||||||
shutil.copytree(r'C:\Python%s\DLLs'%self.py_ver, self.dll_dir,
|
|
||||||
ignore=shutil.ignore_patterns('msvc*.dll', 'Microsoft.*'))
|
|
||||||
for x in QT_DLLS:
|
|
||||||
x += '4.dll'
|
|
||||||
if not x.startswith('phonon'): x = 'Qt'+x
|
|
||||||
shutil.copy2(os.path.join(QT_DIR, 'bin', x), self.dll_dir)
|
|
||||||
shutil.copy2(r'C:\windows\system32\python%s.dll'%self.py_ver,
|
|
||||||
self.dll_dir)
|
|
||||||
for x in os.walk(r'C:\Python%s\Lib'%self.py_ver):
|
|
||||||
for f in x[-1]:
|
|
||||||
if f.lower().endswith('.dll'):
|
|
||||||
f = self.j(x[0], f)
|
|
||||||
if 'py2exe' not in f:
|
|
||||||
shutil.copy2(f, self.dll_dir)
|
|
||||||
shutil.copy2(
|
|
||||||
r'C:\Python%(v)s\Lib\site-packages\pywin32_system32\pywintypes%(v)s.dll'
|
|
||||||
% dict(v=self.py_ver), self.dll_dir)
|
|
||||||
|
|
||||||
def ignore_lib(root, items):
|
|
||||||
ans = []
|
|
||||||
for x in items:
|
|
||||||
ext = os.path.splitext(x)[1]
|
|
||||||
if (not ext and (x in ('demos', 'tests') or 'py2exe' in x)) or \
|
|
||||||
(ext in ('.dll', '.chm', '.htm', '.txt')):
|
|
||||||
ans.append(x)
|
|
||||||
return ans
|
|
||||||
|
|
||||||
shutil.copytree(r'C:\Python%s\Lib'%self.py_ver, self.lib_dir,
|
|
||||||
ignore=ignore_lib)
|
|
||||||
|
|
||||||
# Fix win32com
|
|
||||||
sp_dir = self.j(self.lib_dir, 'site-packages')
|
|
||||||
comext = self.j(sp_dir, 'win32comext')
|
|
||||||
shutil.copytree(self.j(comext, 'shell'), self.j(sp_dir, 'win32com', 'shell'))
|
|
||||||
shutil.rmtree(comext)
|
|
||||||
|
|
||||||
for pat in (r'numpy', r'PyQt4\uic\port_v3'):
|
|
||||||
x = glob.glob(self.j(self.lib_dir, 'site-packages', pat))[0]
|
|
||||||
shutil.rmtree(x)
|
|
||||||
|
|
||||||
self.info('Adding calibre sources...')
|
|
||||||
for x in glob.glob(self.j(self.SRC, '*')):
|
|
||||||
shutil.copytree(x, self.j(sp_dir, self.b(x)))
|
|
||||||
|
|
||||||
for x in (r'calibre\manual', r'calibre\trac', 'pythonwin'):
|
|
||||||
shutil.rmtree(self.j(sp_dir, x))
|
|
||||||
|
|
||||||
for x in os.walk(self.j(sp_dir, 'calibre')):
|
|
||||||
for f in x[-1]:
|
|
||||||
if not f.endswith('.py'):
|
|
||||||
os.remove(self.j(x[0], f))
|
|
||||||
|
|
||||||
self.info('Byte-compiling all python modules...')
|
|
||||||
for x in ('test', 'lib2to3', 'distutils'):
|
|
||||||
shutil.rmtree(self.j(self.lib_dir, x))
|
|
||||||
for x in os.walk(self.lib_dir):
|
|
||||||
root = x[0]
|
|
||||||
for f in x[-1]:
|
|
||||||
if f.endswith('.py'):
|
|
||||||
y = self.j(root, f)
|
|
||||||
rel = os.path.relpath(y, self.lib_dir)
|
|
||||||
try:
|
|
||||||
py_compile.compile(y, dfile=rel, doraise=True)
|
|
||||||
os.remove(y)
|
|
||||||
except:
|
|
||||||
self.warn('Failed to byte-compile', y)
|
|
||||||
pyc, pyo = y+'c', y+'o'
|
|
||||||
epyc, epyo, epy = map(os.path.exists, (pyc,pyo,y))
|
|
||||||
if (epyc or epyo) and epy:
|
|
||||||
os.remove(y)
|
|
||||||
if epyo and epyc:
|
|
||||||
os.remove(pyc)
|
|
||||||
|
|
||||||
self.info('\nAdding Qt plugins...')
|
|
||||||
qt_prefix = QT_DIR
|
|
||||||
plugdir = self.j(qt_prefix, 'plugins')
|
|
||||||
tdir = self.j(self.base, 'qt_plugins')
|
|
||||||
for d in ('imageformats', 'codecs', 'iconengines'):
|
|
||||||
self.info('\t', d)
|
|
||||||
imfd = os.path.join(plugdir, d)
|
|
||||||
tg = os.path.join(tdir, d)
|
|
||||||
if os.path.exists(tg):
|
|
||||||
shutil.rmtree(tg)
|
|
||||||
shutil.copytree(imfd, tg)
|
|
||||||
|
|
||||||
print
|
|
||||||
print 'Adding third party dependencies'
|
|
||||||
tdir = os.path.join(self.base, 'driver')
|
|
||||||
os.makedirs(tdir)
|
|
||||||
for pat in ('*.dll', '*.sys', '*.cat', '*.inf'):
|
|
||||||
for f in glob.glob(os.path.join(LIBUSB_DIR, pat)):
|
|
||||||
shutil.copyfile(f, os.path.join(tdir, os.path.basename(f)))
|
|
||||||
print '\tAdding unrar'
|
|
||||||
shutil.copyfile(LIBUNRAR,
|
|
||||||
os.path.join(self.dll_dir, os.path.basename(LIBUNRAR)))
|
|
||||||
|
|
||||||
print '\tAdding misc binary deps'
|
|
||||||
bindir = os.path.join(SW, 'bin')
|
|
||||||
shutil.copy2(os.path.join(bindir, 'pdftohtml.exe'), self.base)
|
|
||||||
for pat in ('*.dll',):
|
|
||||||
for f in glob.glob(os.path.join(bindir, pat)):
|
|
||||||
ok = True
|
|
||||||
for ex in ('expatw',):
|
|
||||||
if ex in f.lower():
|
|
||||||
ok = False
|
|
||||||
if not ok: continue
|
|
||||||
dest = self.dll_dir
|
|
||||||
if self.b(f).startswith('msvc'):
|
|
||||||
dest = self.base
|
|
||||||
shutil.copy2(f, dest)
|
|
||||||
for x in ('Microsoft.VC90.CRT', 'zlib1.dll', 'libxml2.dll'):
|
|
||||||
dest = self.base if x.startswith('Microsoft') else self.dll_dir
|
|
||||||
shutil.copy2(self.j(bindir, x+'.manifest'), dest)
|
|
||||||
|
|
||||||
shutil.copytree(os.path.join(SW, 'etc', 'fonts'),
|
|
||||||
os.path.join(self.base, 'fontconfig'))
|
|
||||||
# Copy ImageMagick
|
|
||||||
for pat in ('*.dll', '*.xml'):
|
|
||||||
for f in glob.glob(self.j(IMAGEMAGICK, pat)):
|
|
||||||
ok = True
|
|
||||||
for ex in ('magick++', 'x11.dll', 'xext.dll'):
|
|
||||||
if ex in f.lower(): ok = False
|
|
||||||
if not ok: continue
|
|
||||||
shutil.copy2(f, self.dll_dir)
|
|
||||||
|
|
||||||
def embed_manifests(self):
|
|
||||||
self.info('Embedding remaining manifests...')
|
|
||||||
for x in os.walk(self.base):
|
|
||||||
for f in x[-1]:
|
|
||||||
base, ext = os.path.splitext(f)
|
|
||||||
if ext != '.manifest': continue
|
|
||||||
dll = self.j(x[0], base)
|
|
||||||
manifest = self.j(x[0], f)
|
|
||||||
res = 2
|
|
||||||
if os.path.splitext(dll)[1] == '.exe':
|
|
||||||
res = 1
|
|
||||||
if os.path.exists(dll):
|
|
||||||
self.run_builder([MT, '-manifest', manifest,
|
|
||||||
'-outputresource:%s;%d'%(dll,res)])
|
|
||||||
os.remove(manifest)
|
|
||||||
|
|
||||||
def compress(self):
|
|
||||||
self.info('Compressing app dir using 7-zip')
|
|
||||||
subprocess.check_call([r'C:\Program Files\7-Zip\7z.exe', 'a', '-r',
|
|
||||||
'-scsUTF-8', '-sfx', 'winfrozen', 'winfrozen'], cwd=self.base)
|
|
||||||
|
|
||||||
def embed_resources(self, module, desc=None):
|
|
||||||
icon_base = self.j(self.src_root, 'icons')
|
|
||||||
icon_map = {'calibre':'library', 'ebook-viewer':'viewer',
|
|
||||||
'lrfviewer':'viewer'}
|
|
||||||
file_type = 'DLL' if module.endswith('.dll') else 'APP'
|
|
||||||
template = open(self.rc_template, 'rb').read()
|
|
||||||
bname = self.b(module)
|
|
||||||
internal_name = os.path.splitext(bname)[0]
|
|
||||||
icon = icon_map.get(internal_name, 'command-prompt')
|
|
||||||
icon = self.j(icon_base, icon+'.ico')
|
|
||||||
if desc is None:
|
|
||||||
defdesc = 'A dynamic link library' if file_type == 'DLL' else \
|
|
||||||
'An executable program'
|
|
||||||
desc = DESCRIPTIONS.get(internal_name, defdesc)
|
|
||||||
license = 'GNU GPL v3.0'
|
|
||||||
def e(val): return val.replace('"', r'\"')
|
|
||||||
rc = template.format(
|
|
||||||
icon=icon,
|
|
||||||
file_type=e(file_type),
|
|
||||||
file_version=e(WINVER.replace('.', ',')),
|
|
||||||
file_version_str=e(WINVER),
|
|
||||||
file_description=e(desc),
|
|
||||||
internal_name=e(internal_name),
|
|
||||||
original_filename=e(bname),
|
|
||||||
product_version=e(WINVER.replace('.', ',')),
|
|
||||||
product_version_str=e(__version__),
|
|
||||||
product_name=e(__appname__),
|
|
||||||
product_description=e(__appname__+' - E-book management'),
|
|
||||||
legal_copyright=e(license),
|
|
||||||
legal_trademarks=e(__appname__ + \
|
|
||||||
' is a registered U.S. trademark number 3,666,525')
|
|
||||||
)
|
|
||||||
tdir = self.obj_dir
|
|
||||||
rcf = self.j(tdir, bname+'.rc')
|
|
||||||
with open(rcf, 'wb') as f:
|
|
||||||
f.write(rc)
|
|
||||||
res = self.j(tdir, bname + '.res')
|
|
||||||
cmd = [RC, '/n', '/fo'+res, rcf]
|
|
||||||
self.run_builder(cmd)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def install_site_py(self):
|
|
||||||
if not os.path.exists(self.lib_dir):
|
|
||||||
os.makedirs(self.lib_dir)
|
|
||||||
shutil.copy2(self.j(self.d(__file__), 'site.py'), self.lib_dir)
|
|
||||||
y = os.path.join(self.lib_dir, 'site.py')
|
|
||||||
py_compile.compile(y, dfile='site.py', doraise=True)
|
|
||||||
os.remove(y)
|
|
||||||
|
|
||||||
def run_builder(self, cmd):
|
|
||||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
if p.wait() != 0:
|
|
||||||
self.info('Failed to run builder:')
|
|
||||||
self.info(*cmd)
|
|
||||||
self.info(p.stdout.read())
|
|
||||||
self.info(p.stderr.read())
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def build_launchers(self):
|
|
||||||
self.obj_dir = self.j(self.src_root, 'build', 'launcher')
|
|
||||||
if not os.path.exists(self.obj_dir):
|
|
||||||
os.makedirs(self.obj_dir)
|
|
||||||
base = self.j(self.src_root, 'setup', 'installer', 'windows')
|
|
||||||
sources = [self.j(base, x) for x in ['util.c']]
|
|
||||||
headers = [self.j(base, x) for x in ['util.h']]
|
|
||||||
objects = [self.j(self.obj_dir, self.b(x)+'.obj') for x in sources]
|
|
||||||
cflags = '/c /EHsc /MD /W3 /Ox /nologo /D_UNICODE'.split()
|
|
||||||
cflags += ['/DPYDLL="python%s.dll"'%self.py_ver, '/IC:/Python%s/include'%self.py_ver]
|
|
||||||
for src, obj in zip(sources, objects):
|
|
||||||
if not self.newer(obj, headers+[src]): continue
|
|
||||||
cmd = [msvc.cc] + cflags + ['/Fo'+obj, '/Tc'+src]
|
|
||||||
self.run_builder(cmd)
|
|
||||||
|
|
||||||
dll = self.j(self.obj_dir, 'calibre-launcher.dll')
|
|
||||||
ver = '.'.join(__version__.split('.')[:2])
|
|
||||||
if self.newer(dll, objects):
|
|
||||||
cmd = [msvc.linker, '/DLL', '/INCREMENTAL:NO', '/VERSION:'+ver,
|
|
||||||
'/OUT:'+dll, '/nologo', '/MACHINE:X86'] + objects + \
|
|
||||||
[self.embed_resources(dll),
|
|
||||||
'/LIBPATH:C:/Python%s/libs'%self.py_ver,
|
|
||||||
'python%s.lib'%self.py_ver,
|
|
||||||
'/delayload:python%s.dll'%self.py_ver]
|
|
||||||
self.info('Linking calibre-launcher.dll')
|
|
||||||
self.run_builder(cmd)
|
|
||||||
|
|
||||||
src = self.j(base, 'main.c')
|
|
||||||
shutil.copy2(dll, self.base)
|
|
||||||
for typ in ('console', 'gui', ):
|
|
||||||
self.info('Processing %s launchers'%typ)
|
|
||||||
subsys = 'WINDOWS' if typ == 'gui' else 'CONSOLE'
|
|
||||||
for mod, bname, func in zip(modules[typ], basenames[typ],
|
|
||||||
functions[typ]):
|
|
||||||
xflags = list(cflags)
|
|
||||||
if typ == 'gui':
|
|
||||||
xflags += ['/DGUI_APP=']
|
|
||||||
|
|
||||||
xflags += ['/DMODULE="%s"'%mod, '/DBASENAME="%s"'%bname,
|
|
||||||
'/DFUNCTION="%s"'%func]
|
|
||||||
dest = self.j(self.obj_dir, bname+'.obj')
|
|
||||||
if self.newer(dest, [src]+headers):
|
|
||||||
self.info('Compiling', bname)
|
|
||||||
cmd = [msvc.cc] + xflags + ['/Tc'+src, '/Fo'+dest]
|
|
||||||
self.run_builder(cmd)
|
|
||||||
exe = self.j(self.base, bname+'.exe')
|
|
||||||
manifest = exe+'.manifest'
|
|
||||||
lib = dll.replace('.dll', '.lib')
|
|
||||||
if self.newer(exe, [dest, lib, self.rc_template, __file__]):
|
|
||||||
self.info('Linking', bname)
|
|
||||||
cmd = [msvc.linker] + ['/INCREMENTAL:NO', '/MACHINE:X86',
|
|
||||||
'/LIBPATH:'+self.obj_dir, '/SUBSYSTEM:'+subsys,
|
|
||||||
'/LIBPATH:C:/Python%s/libs'%self.py_ver, '/RELEASE',
|
|
||||||
'/OUT:'+exe, self.embed_resources(exe),
|
|
||||||
dest, lib]
|
|
||||||
self.run_builder(cmd)
|
|
||||||
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
|||||||
<Media Id="1" Cabinet="{app}.cab" CompressionLevel="{compression}" EmbedCab="yes" />
|
<Media Id="1" Cabinet="{app}.cab" CompressionLevel="{compression}" EmbedCab="yes" />
|
||||||
|
|
||||||
<Directory Id='TARGETDIR' Name='SourceDir'>
|
<Directory Id='TARGETDIR' Name='SourceDir'>
|
||||||
|
<Merge Id="VCRedist" SourceFile="{crt_msm}" DiskId="1" Language="0"/>
|
||||||
<Directory Id='ProgramFilesFolder' Name='PFiles'>
|
<Directory Id='ProgramFilesFolder' Name='PFiles'>
|
||||||
<Directory Id='APPLICATIONFOLDER' Name='{app}' />
|
<Directory Id='APPLICATIONFOLDER' Name='{app}' />
|
||||||
</Directory>
|
</Directory>
|
||||||
@ -70,6 +71,10 @@
|
|||||||
Description="All the files need to run {app}" Absent="disallow">
|
Description="All the files need to run {app}" Absent="disallow">
|
||||||
</Feature>
|
</Feature>
|
||||||
|
|
||||||
|
<Feature Id="VCRedist" Title="Visual C++ 8.0 Runtime" AllowAdvertise="no" Display="hidden" Level="1">
|
||||||
|
<MergeRef Id="VCRedist"/>
|
||||||
|
</Feature>
|
||||||
|
|
||||||
<Feature Id="FSMS" Title="Start menu shortcuts" Level="1"
|
<Feature Id="FSMS" Title="Start menu shortcuts" Level="1"
|
||||||
Description="Program shortcuts installed in the Start Menu">
|
Description="Program shortcuts installed in the Start Menu">
|
||||||
<ComponentRef Id="StartMenuShortcuts"/>
|
<ComponentRef Id="StartMenuShortcuts"/>
|
||||||
@ -100,16 +105,16 @@
|
|||||||
</UI>
|
</UI>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Set default folder name and choose per user install by default.
|
Set default folder name and allow only per machine installs.
|
||||||
For a per-machine installation, the default installation location
|
For a per-machine installation, the default installation location
|
||||||
will be [ProgramFilesFolder][ApplicationFolderName] and the user
|
will be [ProgramFilesFolder][ApplicationFolderName] and the user
|
||||||
will be able to change it in the setup UI. For a per-user installation,
|
will be able to change it in the setup UI. This is because the installer
|
||||||
the default installation location will be
|
has to install the VC90 merge module into the system winsxs folder for python
|
||||||
[LocalAppDataFolder]Apps\[ApplicationFolderName] and the user will not
|
to work, so per user installs are impossible anyway.
|
||||||
be able to change it in the setup UI.
|
|
||||||
-->
|
-->
|
||||||
<Property Id="ApplicationFolderName" Value="Calibre - E-book Management" />
|
<Property Id="ApplicationFolderName" Value="Calibre - E-book Management" />
|
||||||
<Property Id="WixAppFolder" Value="WixPerUserFolder" />
|
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
|
||||||
|
<WixVariable Id="WixUISupportPerUser" Value="0" />
|
||||||
|
|
||||||
<!-- Add option to launch calibre after install -->
|
<!-- Add option to launch calibre after install -->
|
||||||
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch {app}" />
|
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch {app}" />
|
||||||
|
@ -38,6 +38,7 @@ class WixMixIn:
|
|||||||
exe_map = self.smap,
|
exe_map = self.smap,
|
||||||
main_icon = self.j(self.src_root, 'icons', 'library.ico'),
|
main_icon = self.j(self.src_root, 'icons', 'library.ico'),
|
||||||
web_icon = self.j(self.src_root, 'icons', 'web.ico'),
|
web_icon = self.j(self.src_root, 'icons', 'web.ico'),
|
||||||
|
crt_msm = self.j(self.SW, 'Microsoft_VC90_CRT_x86.msm')
|
||||||
)
|
)
|
||||||
template = open(self.j(self.d(__file__), 'en-us.xml'),
|
template = open(self.j(self.d(__file__), 'en-us.xml'),
|
||||||
'rb').read()
|
'rb').read()
|
||||||
@ -60,10 +61,15 @@ class WixMixIn:
|
|||||||
self.installer = self.j(self.installer, '%s-%s.msi' % (__appname__,
|
self.installer = self.j(self.installer, '%s-%s.msi' % (__appname__,
|
||||||
__version__))
|
__version__))
|
||||||
license = self.j(self.src_root, 'LICENSE.rtf')
|
license = self.j(self.src_root, 'LICENSE.rtf')
|
||||||
|
banner = self.j(self.src_root, 'icons', 'wix-banner.bmp')
|
||||||
|
dialog = self.j(self.src_root, 'icons', 'wix-dialog.bmp')
|
||||||
cmd = [LIGHT, '-nologo', '-ext', 'WixUIExtension',
|
cmd = [LIGHT, '-nologo', '-ext', 'WixUIExtension',
|
||||||
'-cultures:en-us', '-loc', enusf, wixobj,
|
'-cultures:en-us', '-loc', enusf, wixobj,
|
||||||
'-ext', 'WixUtilExtension',
|
'-ext', 'WixUtilExtension',
|
||||||
'-o', self.installer, '-dWixUILicenseRtf='+license]
|
'-o', self.installer,
|
||||||
|
'-dWixUILicenseRtf='+license,
|
||||||
|
'-dWixUIBannerBmp='+banner,
|
||||||
|
'-dWixUIDialogBmp='+dialog]
|
||||||
cmd.append('-sice:ICE60') # No language in dlls warning
|
cmd.append('-sice:ICE60') # No language in dlls warning
|
||||||
if self.opts.no_ice:
|
if self.opts.no_ice:
|
||||||
cmd.append('-sval')
|
cmd.append('-sval')
|
||||||
|
@ -26,8 +26,6 @@ else:
|
|||||||
Structure = _Structure
|
Structure = _Structure
|
||||||
if hasattr(sys, 'frozen') and iswindows:
|
if hasattr(sys, 'frozen') and iswindows:
|
||||||
lp = os.path.join(os.path.dirname(sys.executable), 'DLLs', 'unrar.dll')
|
lp = os.path.join(os.path.dirname(sys.executable), 'DLLs', 'unrar.dll')
|
||||||
if not os.path.exists(lp):
|
|
||||||
lp = os.path.join(os.path.dirname(sys.executable), 'unrar.dll')
|
|
||||||
_libunrar = cdll.LoadLibrary(lp)
|
_libunrar = cdll.LoadLibrary(lp)
|
||||||
else:
|
else:
|
||||||
_libunrar = load_library(_librar_name, cdll)
|
_libunrar = load_library(_librar_name, cdll)
|
||||||
|
@ -78,7 +78,7 @@ Device Integration
|
|||||||
|
|
||||||
What devices does |app| support?
|
What devices does |app| support?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
At the moment |app| has full support for the SONY PRS 300/500/505/600/700, Cybook Gen 3/Opus, Amazon Kindle 1/2/DX, Netronix EB600, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Adroid phones and the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
At the moment |app| has full support for the SONY PRS 300/500/505/600/700, Cybook Gen 3/Opus, Amazon Kindle 1/2/DX, Netronix EB600, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, Android phones and the iPhone. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
||||||
|
|
||||||
I used |app| to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?
|
I used |app| to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -145,7 +145,9 @@ else:
|
|||||||
data = dict(version = version, name='windows',
|
data = dict(version = version, name='windows',
|
||||||
installer_name='Windows installer',
|
installer_name='Windows installer',
|
||||||
title='Download %s for windows'%(__appname__),
|
title='Download %s for windows'%(__appname__),
|
||||||
compatibility='%s works on Windows XP and Windows Vista.'%(__appname__,),
|
compatibility=('%(a)s works on Windows XP, Vista and 7.'
|
||||||
|
'If you are upgrading from a version older than 0.6.17, '
|
||||||
|
'please uninstall %(a)s first.')%dict(a=__appname__,),
|
||||||
path=MOBILEREAD+file, app=__appname__,
|
path=MOBILEREAD+file, app=__appname__,
|
||||||
note=Markup(\
|
note=Markup(\
|
||||||
'''
|
'''
|
||||||
|
@ -82,8 +82,6 @@ if isosx:
|
|||||||
_lib = util.find_library('Wand')
|
_lib = util.find_library('Wand')
|
||||||
elif iswindows:
|
elif iswindows:
|
||||||
flib = os.path.join(os.path.dirname(sys.executable), 'DLLs', 'CORE_RL_wand_.dll')
|
flib = os.path.join(os.path.dirname(sys.executable), 'DLLs', 'CORE_RL_wand_.dll')
|
||||||
if not os.path.exists(flib):
|
|
||||||
flib = os.path.join(os.path.dirname(sys.executable), 'CORE_RL_wand_.dll')
|
|
||||||
_lib = flib if isfrozen else 'CORE_RL_wand_'
|
_lib = flib if isfrozen else 'CORE_RL_wand_'
|
||||||
else:
|
else:
|
||||||
if isfrozen:
|
if isfrozen:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user