IGN:Rationalize automated build process

This commit is contained in:
Kovid Goyal 2008-06-15 16:30:44 -07:00
parent 30a01e4484
commit 908e31a80c
15 changed files with 282 additions and 211 deletions

View File

@ -1,8 +1,10 @@
PYTHON = python
all : plugins pictureflow gui2 translations resources
all : plugins gui2 translations resources
plugins:
plugins : src/calibre/plugins pictureflow
src/calibre/plugins:
mkdir -p src/calibre/plugins
clean :

153
linux_installer.py Normal file
View File

@ -0,0 +1,153 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
'''
Create linux binary.
'''
import glob, sys, subprocess, tarfile, os, re
HOME = '/home/kovid'
PYINSTALLER = os.path.expanduser('~/build/pyinstaller')
CALIBREPREFIX = '___'
CLIT = '/usr/bin/clit'
PDFTOHTML = '/usr/bin/pdftohtml'
LIBUNRAR = '/usr/lib/libunrar.so'
QTDIR = '/usr/lib/qt4'
QTDLLS = ('QtCore', 'QtGui', 'QtNetwork', 'QtSvg', 'QtXml')
EXTRAS = ('/usr/lib/python2.5/site-packages/PIL', os.path.expanduser('~/ipython/IPython'))
CALIBRESRC = os.path.join(CALIBREPREFIX, 'src')
CALIBREPLUGINS = os.path.join(CALIBRESRC, 'calibre', 'plugins')
sys.path.insert(0, CALIBRESRC)
from calibre import __version__
def run_pyinstaller(args=sys.argv):
subprocess.check_call(('/usr/bin/sudo', 'chown', '-R', 'kovid:users', glob.glob('/usr/lib/python*/site-packages/')[-1]))
subprocess.check_call('rm -rf %(py)s/dist/* %(py)s/build/*'%dict(py=PYINSTALLER), shell=True)
subprocess.check_call('make plugins', shell=True)
cp = HOME+'/build/'+os.path.basename(os.getcwd())
spec = open(os.path.join(PYINSTALLER, 'calibre', 'calibre.spec'), 'wb')
raw = re.sub(r'CALIBREPREFIX\s+=\s+\'___\'', 'CALIBREPREFIX = '+repr(cp),
open(__file__).read())
spec.write(raw)
spec.close()
os.chdir(PYINSTALLER)
subprocess.check_call('python -OO Build.py calibre/calibre.spec', shell=True)
return 0
if __name__ == '__main__' and 'linux_installer.py' in __file__:
sys.exit(run_pyinstaller())
loader = os.path.join(os.path.expanduser('~/temp'), 'calibre_installer_loader.py')
if not os.path.exists(loader):
open(loader, 'wb').write('''
import sys, os
sys.frozen_path = os.getcwd()
os.chdir(os.environ.get("ORIGWD", "."))
sys.path.insert(0, os.path.join(sys.frozen_path, "library.pyz"))
sys.path.insert(0, sys.frozen_path)
from PyQt4.QtCore import QCoreApplication
QCoreApplication.setLibraryPaths([sys.frozen_path, os.path.join(sys.frozen_path, "plugins")])
''')
excludes = ['gtk._gtk', 'gtk.glade', 'qt', 'matplotlib.nxutils', 'matplotlib._cntr',
'matplotlib.ttconv', 'matplotlib._image', 'matplotlib.ft2font',
'matplotlib._transforms', 'matplotlib._agg', 'matplotlib.backends._backend_agg',
'matplotlib.axes', 'matplotlib', 'matplotlib.pyparsing',
'TKinter', 'atk', 'gobject._gobject', 'pango', 'PIL', 'Image', 'IPython']
temp = ['keyword', 'codeop']
recipes = ['calibre', 'web', 'feeds', 'recipes']
prefix = '.'.join(recipes)+'.'
for f in glob.glob(os.path.join(CALIBRESRC, *(recipes+['*.py']))):
temp.append(prefix + os.path.basename(f).partition('.')[0])
hook = os.path.expanduser('~/temp/hook-calibre.py')
f = open(hook, 'wb')
hook_script = 'hiddenimports = %s'%repr(temp)
f.write(hook_script)
sys.path.insert(0, CALIBRESRC)
from calibre.linux import entry_points
executables, scripts = ['calibre_postinstall', 'parallel'], \
[os.path.join(CALIBRESRC, 'calibre', 'linux.py'), os.path.join(CALIBRESRC, 'calibre', 'parallel.py')]
for entry in entry_points['console_scripts'] + entry_points['gui_scripts']:
fields = entry.split('=')
executables.append(fields[0].strip())
scripts.append(os.path.join(CALIBRESRC, *map(lambda x: x.strip(), fields[1].split(':')[0].split('.')))+'.py')
recipes = Analysis(glob.glob(os.path.join(CALIBRESRC, 'calibre', 'web', 'feeds', 'recipes', '*.py')),
pathex=[CALIBRESRC], hookspath=[os.path.dirname(hook)], excludes=excludes)
analyses = [Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), loader, script],
pathex=[PYINSTALLER, CALIBRESRC, CALIBREPLUGINS], excludes=excludes) for script in scripts]
pyz = TOC()
binaries = TOC()
for a in analyses:
pyz = a.pure + pyz
binaries = a.binaries + binaries
pyz = PYZ(pyz + recipes.pure, name='library.pyz')
built_executables = []
for script, exe, a in zip(scripts, executables, analyses):
built_executables.append(EXE(PYZ(TOC()),
a.scripts+[('O','','OPTION'),],
exclude_binaries=1,
name=os.path.join('buildcalibre', exe),
debug=False,
strip=True,
upx=False,
excludes=excludes,
console=1))
print 'Adding plugins...'
for f in glob.glob(os.path.join(CALIBREPLUGINS, '*.so')):
binaries += [(os.path.basename(f), f, 'BINARY')]
print 'Adding external programs...'
binaries += [('clit', CLIT, 'BINARY'), ('pdftohtml', PDFTOHTML, 'BINARY'),
('libunrar.so', LIBUNRAR, 'BINARY')]
qt = []
for dll in QTDLLS:
path = os.path.join(QTDIR, 'lib'+dll+'.so.4')
qt.append((os.path.basename(path), path, 'BINARY'))
binaries += qt
plugins = []
plugdir = os.path.join(QTDIR, 'plugins')
for dirpath, dirnames, filenames in os.walk(plugdir):
for f in filenames:
if not f.endswith('.so') or 'designer' in dirpath or 'codcs' in dirpath or 'sqldrivers' in dirpath : continue
f = os.path.join(dirpath, f)
plugins.append(('plugins/'+f.replace(plugdir, ''), f, 'BINARY'))
binaries += plugins
manifest = '/tmp/manifest'
open(manifest, 'wb').write('\\n'.join(executables))
version = '/tmp/version'
open(version, 'wb').write(__version__)
coll = COLLECT(binaries, pyz,
[('manifest', manifest, 'DATA'), ('version', version, 'DATA')],
*built_executables,
**dict(strip=True,
upx=False,
excludes=excludes,
name='dist'))
os.chdir(os.path.join(HOMEPATH, 'calibre', 'dist'))
for folder in EXTRAS:
subprocess.check_call('cp -rf %s .'%folder, shell=True)
print 'Building tarball...'
tbz2 = 'calibre-%s-i686.tar.bz2'%__version__
tf = tarfile.open(os.path.join('/tmp', tbz2), 'w:bz2')
for f in os.listdir('.'):
tf.add(f)

View File

@ -99,8 +99,7 @@ _check_symlinks_prescript()
includes=list(self.includes) + main_modules['console'],
packages=self.packages,
excludes=self.excludes,
debug=debug
)
debug=debug)
@classmethod
def makedmg(cls, d, volname,
@ -249,6 +248,11 @@ _check_symlinks_prescript()
else:
os.link(src, os.path.join(module_dir, dest))
print
print 'Adding IPython'
dst = os.path.join(resource_dir, 'lib', 'python2.5', 'IPython')
if os.path.exists(dst): shutil.rmtree(dst)
shutil.copytree(os.path.expanduser('~/build/ipython/IPython'), dst)
print
print 'Installing prescipt'
sf = [os.path.basename(s) for s in all_names]
cs = BuildAPP.CHECK_SYMLINKS_PRESCRIPT % dict(dest_path=repr('/usr/bin'),
@ -294,12 +298,12 @@ def main():
'PyQt4.QtSvg',
'mechanize', 'ClientForm', 'usbobserver',
'genshi', 'calibre.web.feeds.recipes.*',
'IPython.Extensions.*', 'pydoc'],
'keyword', 'codeop', 'pydoc'],
'packages' : ['PIL', 'Authorization', 'rtf2xml', 'lxml'],
'excludes' : [],
'excludes' : ['IPython'],
'plist' : { 'CFBundleGetInfoString' : '''calibre, an E-book management application.'''
''' Visit http://calibre.kovidgoyal.net for details.''',
'CFBundleIdentifier':'net.kovidgoyal.librs500',
'CFBundleIdentifier':'net.kovidgoyal.calibre',
'CFBundleShortVersionString':VERSION,
'CFBundleVersion':APPNAME + ' ' + VERSION,
'LSMinimumSystemVersion':'10.4.3',

View File

@ -7,9 +7,9 @@ import re, os
from PyQt4.QtGui import QListView, QIcon, QFont, QLabel, QListWidget, \
QListWidgetItem, QTextCharFormat, QApplication, \
QSyntaxHighlighter, QCursor, QColor, QWidget, \
QAbstractItemDelegate, QPixmap, QStyle
QAbstractItemDelegate, QPixmap, QStyle, QFontMetrics
from PyQt4.QtCore import QAbstractListModel, QVariant, Qt, SIGNAL, \
QObject, QRegExp, QRectF, QString
QObject, QRegExp, QString
from calibre.gui2.jobs import DetailView
from calibre.gui2 import human_readable, NONE, TableView, qstring_to_unicode, error_dialog
@ -128,8 +128,10 @@ class LocationDelegate(QAbstractItemDelegate):
def rects(self, option):
style = QApplication.style()
font = QFont(option.font)
font.setBold(True)
irect = style.itemPixmapRect(option.rect, Qt.AlignHCenter|Qt.AlignTop, self.pixmap)
trect = style.itemTextRect(option.fontMetrics, option.rect,
trect = style.itemTextRect(QFontMetrics(font), option.rect,
Qt.AlignHCenter|Qt.AlignTop, True, self.text)
trect.moveTop(irect.bottom())
return irect, trect

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n"

View File

@ -17,7 +17,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#~ msgid ""

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n"

View File

@ -11,13 +11,13 @@ msgstr ""
"Project-Id-Version: es\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2008-06-12 20:18+0000\n"
"PO-Revision-Date: 2008-06-12 22:40+0000\n"
"PO-Revision-Date: 2008-06-15 08:31+0000\n"
"Last-Translator: S. Dorscht <Unknown>\n"
"Language-Team: Spanish\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#~ msgid ""
@ -151,7 +151,7 @@ msgstr "Creado por "
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:146
#: /home/kovid/work/calibre/src/calibre/devices/prs505/driver.py:174
msgid "Unable to detect the %s disk drive. Try rebooting."
msgstr ""
msgstr "No se ha podido detectar la unidad de disco %s. Trate de reiniciar."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:73
msgid "Set the title. Default: filename."
@ -671,7 +671,6 @@ msgid "Creating XML..."
msgstr "Creando XML..."
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/lrfparser.py:156
#, fuzzy
msgid "LRS written to "
msgstr "LRS escrito en "
@ -1130,7 +1129,6 @@ msgid "Show &text in toolbar buttons"
msgstr "Mostrar &texto en los botones de la barra de herramientas"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/config_ui.py:219
#, fuzzy
msgid "Free unused diskspace from the database"
msgstr "Espacio de disco disponible de la base de datos"
@ -1896,18 +1894,16 @@ msgstr ""
"actual"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:63
#, fuzzy
msgid "No recipe selected"
msgstr "No hay ninguna receta seleccionada"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:69
#, fuzzy
msgid "The attached file: %s is a recipe to download %s."
msgstr "el archivo adjunto: %s es una receta para descargar %s"
msgstr "El archivo adjunto: %s es una receta para descargar %s"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:70
msgid "Recipe for "
msgstr ""
msgstr "Receta para "
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:86
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:96
@ -1941,9 +1937,8 @@ msgid "Already exists"
msgstr "Ya existe"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:121
#, fuzzy
msgid "This feed has already been added to the recipe"
msgstr "el Feed ya se ha añadido a la receta"
msgstr "Este Feed ya se ha añadido a la receta"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:162
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:171
@ -1968,9 +1963,8 @@ msgid "A custom recipe named %s already exists. Do you want to replace it?"
msgstr "una receta personalizada llamada %s ya existe. Quiere reemplazarla?"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:187
#, fuzzy
msgid "Choose a recipe file"
msgstr "Seleccionarr un archivo de receta"
msgstr "Seleccionar un archivo de receta"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles.py:187
msgid "Recipes"
@ -2651,6 +2645,9 @@ msgid ""
"href=\"http://calibre.kovidgoyal.net/wiki/Changelog\">new features</a>. "
"Visit the download page?"
msgstr ""
"%s se ha actualizado a la versión %s. Ver las <a "
"href=\"http://calibre.kovidgoyal.net/wiki/Changelog\">nuevas "
"características</a>. Visita la página de descarga?"
#: /home/kovid/work/calibre/src/calibre/gui2/main.py:1155
msgid "Update available"
@ -2833,6 +2830,8 @@ msgid ""
"Path to the calibre database. Default is to use the path stored in the "
"settings."
msgstr ""
"Camino a la base de datos calibre. El valor predeterminado es a usar la ruta "
"almacenada en la configuración."
#: /home/kovid/work/calibre/src/calibre/library/cli.py:80
msgid ""
@ -2840,6 +2839,9 @@ msgid ""
"\n"
"List the books available in the calibre database. \n"
msgstr ""
"%prog list [options]\n"
"\n"
"Mostrar los libros disponibles en la base de datos calibre. \n"
#: /home/kovid/work/calibre/src/calibre/library/cli.py:88
msgid ""
@ -2866,6 +2868,9 @@ msgid ""
"please see the search related documentation in the User Manual. Default is "
"to do no filtering."
msgstr ""
"Filtrar los resultados de la consulta de búsqueda. Para el formato de la "
"consulta de búsqueda consulte la documentación relacionada con la búsqueda "
"en el Manual del usuario. El valor predeterminado es a no hacer el filtrado."
#: /home/kovid/work/calibre/src/calibre/library/cli.py:101
msgid "Invalid fields. Available fields:"
@ -2891,12 +2896,20 @@ msgid ""
"directories, see\n"
"the directory related options below. \n"
msgstr ""
"%prog add [options] file1 file2 file3 ...\n"
"\n"
"Añadir los archivos especificados como libros a la base de datos. También "
"puede especificar\n"
"directorios, consulte las opciones relacionadas a los directorios más abajo. "
"\n"
#: /home/kovid/work/calibre/src/calibre/library/cli.py:204
msgid ""
"Assume that each directory has only a single logical book and that all files "
"in it are different e-book formats of that book"
msgstr ""
"Supongamos que cada directorio tiene un solo libro lógico y que todos los "
"archivos en este directorio son diferentes formatos de este libro"
#: /home/kovid/work/calibre/src/calibre/library/cli.py:206
msgid "Process directories recursively"
@ -2922,6 +2935,12 @@ msgid ""
"separated list of id numbers (you can get id numbers by using the list "
"command). For example, 23,34,57-85\n"
msgstr ""
"%prog remove ids\n"
"\n"
"Eliminar los libros identificados por ID de la base de datos. ID debe ser "
"una lista separada por comas de números de identificación (se puede obtener "
"números de identificación utilizando el commando \"list\"). Por ejemplo, "
"23,34,57-85\n"
#: /home/kovid/work/calibre/src/calibre/library/cli.py:243
msgid "You must specify at least one book to remove"
@ -2953,6 +2972,13 @@ msgid ""
"by using the list command. fmt should be a file extension like LRF or TXT or "
"EPUB. If the logical book does not have fmt available, do nothing.\n"
msgstr ""
"\n"
"%prog remove_format [options] id fmt\n"
"\n"
"Eliminar el formato fmt del libro lógico identificado por id. Usted puede "
"obtener id utilizando el comando \"list\". fmt debe ser una extensión de "
"archivo como LRF o TXT o EPUB. Si el libro lógico no tiene fmt disponible, "
"no hacer nada.\n"
#: /home/kovid/work/calibre/src/calibre/library/cli.py:300
msgid "You must specify an id and a format"
@ -2976,11 +3002,11 @@ msgstr "Trabajo detenido por el usuario"
#: /home/kovid/work/calibre/src/calibre/utils/fontconfig.py:124
msgid "Could not initialize the fontconfig library"
msgstr ""
msgstr "No se ha podido inicializar la biblioteca fontconfig"
#: /home/kovid/work/calibre/src/calibre/utils/sftp.py:53
msgid "URL must have the scheme sftp"
msgstr ""
msgstr "La URL debe tener el régimen de sftp"
#: /home/kovid/work/calibre/src/calibre/utils/sftp.py:57
msgid "host must be of the form user@hostname"
@ -2988,11 +3014,11 @@ msgstr ""
#: /home/kovid/work/calibre/src/calibre/utils/sftp.py:68
msgid "Failed to negotiate SSH session: "
msgstr ""
msgstr "No se ha podido negociar período de sesiones SSH: "
#: /home/kovid/work/calibre/src/calibre/utils/sftp.py:71
msgid "Failed to authenticate with server: %s"
msgstr ""
msgstr "No se ha podido autenticar con el servidor: %s"
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:56
#: /home/kovid/work/calibre/src/calibre/web/feeds/__init__.py:77

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n"

View File

@ -15,7 +15,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n"

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n"

View File

@ -14,7 +14,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#~ msgid ""

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n"

View File

@ -13,7 +13,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2008-06-14 07:16+0000\n"
"X-Launchpad-Export-Date: 2008-06-15 22:20+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"Generated-By: pygettext.py 1.5\n"

220
upload.py
View File

@ -1,13 +1,19 @@
#!/usr/bin/python
import sys, os, shutil, time, tempfile, socket
import sys, os, shutil, time, tempfile, socket, fcntl, struct
sys.path.append('src')
import subprocess
from subprocess import check_call as _check_call
from functools import partial
#from pyvix.vix import Host, VIX_SERVICEPROVIDER_VMWARE_WORKSTATION
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('google.com', 0))
HOST=s.getsockname()[0]
def get_ip_address(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', ifname[:15])
)[20:24])
HOST=get_ip_address('eth0')
PROJECT=os.path.basename(os.getcwd())
from calibre import __version__, __appname__
@ -21,11 +27,12 @@ TXT2LRF = "src/calibre/ebooks/lrf/txt/demo"
BUILD_SCRIPT ='''\
#!/bin/bash
cd ~/build && \
rsync -avz --exclude docs --exclude .bzr --exclude .build --exclude build --exclude dist --exclude "*.pyc" --exclude "*.pyo" rsync://%(host)s/work/%(project)s . && \
rsync -avz --exclude src/calibre/plugins --exclude docs --exclude .bzr --exclude .build --exclude build --exclude dist --exclude "*.pyc" --exclude "*.pyo" rsync://%(host)s/work/%(project)s . && \
cd %(project)s && \
mkdir -p build dist && \
mkdir -p build dist src/calibre/plugins && \
%%s && \
rm -rf build/* dist/* && \
python %%s
%%s %%s
'''%dict(host=HOST, project=PROJECT)
check_call = partial(_check_call, shell=True)
#h = Host(hostType=VIX_SERVICEPROVIDER_VMWARE_WORKSTATION)
@ -41,22 +48,24 @@ def installer_name(ext):
return 'dist/%s-%s.%s'%(__appname__, __version__, ext)
return 'dist/%s-%s-i686.%s'%(__appname__, __version__, ext)
def start_vm(vm, ssh_host, build_script, sleep):
def start_vm(vm, ssh_host, build_script, sleep=75):
vmware = ('vmware', '-q', '-x', '-n', vm)
subprocess.Popen(vmware)
t = tempfile.NamedTemporaryFile(suffix='.sh')
t.write(build_script)
t.flush()
print 'Waiting for VM to startup'
time.sleep(sleep)
while subprocess.call('ping -q -c1 '+ssh_host, shell=True, stdout=open('/dev/null', 'w')) != 0:
time.sleep(5)
time.sleep(20)
print 'Trying to SSH into VM'
subprocess.check_call(('scp', t.name, ssh_host+':build-'+PROJECT))
subprocess.check_call('ssh -t %s bash build-%s'%(ssh_host, PROJECT), shell=True)
def build_windows():
installer = installer_name('exe')
vm = '/vmware/Windows XP/Windows XP Professional.vmx'
start_vm(vm, 'windows', BUILD_SCRIPT%'windows_installer.py', 75)
subprocess.check_call(('ssh', 'windows', '/bin/bash', '~/build-'+PROJECT))
start_vm(vm, 'windows', BUILD_SCRIPT%('python setup.py develop', 'python','windows_installer.py'))
subprocess.check_call(('scp', 'windows:build/%s/dist/*.exe'%PROJECT, 'dist'))
if not os.path.exists(installer):
raise Exception('Failed to build installer '+installer)
@ -66,160 +75,24 @@ def build_windows():
def build_osx():
installer = installer_name('dmg')
vm = '/vmware/Mac OSX/Mac OSX.vmx'
vmware = ('vmware', '-q', '-x', '-n', vm)
start_vm(vm, 'osx', BUILD_SCRIPT%'osx_installer.py', 120)
subprocess.check_call(('ssh', 'osx', '/bin/bash', '~/build-'+PROJECT))
subprocess.check_call(('scp', 'windows:build/%s/dist/*.dmg'%PROJECT, 'dist'))
python = '/Library/Frameworks/Python.framework/Versions/Current/bin/python'
start_vm(vm, 'osx', BUILD_SCRIPT%('sudo %s setup.py develop'%python, python, 'osx_installer.py'))
subprocess.check_call(('scp', 'osx:build/%s/dist/*.dmg'%PROJECT, 'dist'))
if not os.path.exists(installer):
raise Exception('Failed to build installer '+installer)
subprocess.Popen(('ssh', 'osx', 'sudo', '/sbin/shutdown', '-h', 'now'))
return os.path.basename(installer)
def _build_linux():
cwd = os.getcwd()
tbz2 = os.path.join(cwd, installer_name('tar.bz2'))
SPEC="""\
import os
HOME = '%(home)s'
PYINSTALLER = os.path.expanduser('~/build/pyinstaller')
CALIBREPREFIX = HOME+'/work/%(project)s'
CLIT = '/usr/bin/clit'
PDFTOHTML = '/usr/bin/pdftohtml'
LIBUNRAR = '/usr/lib/libunrar.so'
QTDIR = '/usr/lib/qt4'
QTDLLS = ('QtCore', 'QtGui', 'QtNetwork', 'QtSvg', 'QtXml')
EXTRAS = ('/usr/lib/python2.5/site-packages/PIL', os.path.expanduser('~/ipython/IPython'))
import glob, sys, subprocess, tarfile
CALIBRESRC = os.path.join(CALIBREPREFIX, 'src')
CALIBREPLUGINS = os.path.join(CALIBRESRC, 'calibre', 'plugins')
subprocess.check_call(('/usr/bin/sudo', 'chown', '-R', 'kovid:users', glob.glob('/usr/lib/python*/site-packages/')[-1]))
subprocess.check_call('rm -rf %%(py)s/dist/* %%(py)s/build/*'%%dict(py=PYINSTALLER), shell=True)
loader = os.path.join('/tmp', 'calibre_installer_loader.py')
if not os.path.exists(loader):
open(loader, 'wb').write('''
import sys, os
sys.frozen_path = os.getcwd()
os.chdir(os.environ.get("ORIGWD", "."))
sys.path.insert(0, os.path.join(sys.frozen_path, "library.pyz"))
sys.path.insert(0, sys.frozen_path)
from PyQt4.QtCore import QCoreApplication
QCoreApplication.setLibraryPaths([sys.frozen_path, os.path.join(sys.frozen_path, "plugins")])
''')
excludes = ['gtk._gtk', 'gtk.glade', 'qt', 'matplotlib.nxutils', 'matplotlib._cntr',
'matplotlib.ttconv', 'matplotlib._image', 'matplotlib.ft2font',
'matplotlib._transforms', 'matplotlib._agg', 'matplotlib.backends._backend_agg',
'matplotlib.axes', 'matplotlib', 'matplotlib.pyparsing',
'TKinter', 'atk', 'gobject._gobject', 'pango', 'PIL', 'Image', 'IPython']
temp = ['keyword', 'codeop']
recipes = ['calibre', 'web', 'feeds', 'recipes']
prefix = '.'.join(recipes)+'.'
for f in glob.glob(os.path.join(CALIBRESRC, *(recipes+['*.py']))):
temp.append(prefix + os.path.basename(f).partition('.')[0])
hook = '/tmp/hook-calibre.py'
open(hook, 'wb').write('hiddenimports = %%s'%%repr(temp) + '\\n')
sys.path.insert(0, CALIBRESRC)
from calibre.linux import entry_points
executables, scripts = ['calibre_postinstall', 'parallel'], \
[os.path.join(CALIBRESRC, 'calibre', 'linux.py'), os.path.join(CALIBRESRC, 'calibre', 'parallel.py')]
for entry in entry_points['console_scripts'] + entry_points['gui_scripts']:
fields = entry.split('=')
executables.append(fields[0].strip())
scripts.append(os.path.join(CALIBRESRC, *map(lambda x: x.strip(), fields[1].split(':')[0].split('.')))+'.py')
recipes = Analysis(glob.glob(os.path.join(CALIBRESRC, 'calibre', 'web', 'feeds', 'recipes', '*.py')),
pathex=[CALIBRESRC], hookspath=[os.path.dirname(hook)], excludes=excludes)
analyses = [Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), loader, script],
pathex=[PYINSTALLER, CALIBRESRC, CALIBREPLUGINS], excludes=excludes) for script in scripts]
pyz = TOC()
binaries = TOC()
for a in analyses:
pyz = a.pure + pyz
binaries = a.binaries + binaries
pyz = PYZ(pyz + recipes.pure, name='library.pyz')
built_executables = []
for script, exe, a in zip(scripts, executables, analyses):
built_executables.append(EXE(PYZ(TOC()),
a.scripts+[('O','','OPTION'),],
exclude_binaries=1,
name=os.path.join('buildcalibre', exe),
debug=False,
strip=True,
upx=False,
excludes=excludes,
console=1))
print 'Adding plugins...'
for f in glob.glob(os.path.join(CALIBREPLUGINS, '*.so')):
binaries += [(os.path.basename(f), f, 'BINARY')]
print 'Adding external programs...'
binaries += [('clit', CLIT, 'BINARY'), ('pdftohtml', PDFTOHTML, 'BINARY'),
('libunrar.so', LIBUNRAR, 'BINARY')]
qt = []
for dll in QTDLLS:
path = os.path.join(QTDIR, 'lib'+dll+'.so.4')
qt.append((os.path.basename(path), path, 'BINARY'))
binaries += qt
plugins = []
plugdir = os.path.join(QTDIR, 'plugins')
for dirpath, dirnames, filenames in os.walk(plugdir):
for f in filenames:
if not f.endswith('.so') or 'designer' in dirpath or 'codcs' in dirpath or 'sqldrivers' in dirpath : continue
f = os.path.join(dirpath, f)
plugins.append(('plugins/'+f.replace(plugdir, ''), f, 'BINARY'))
binaries += plugins
manifest = '/tmp/manifest'
open(manifest, 'wb').write('\\n'.join(executables))
from calibre import __version__
version = '/tmp/version'
open(version, 'wb').write(__version__)
coll = COLLECT(binaries, pyz, [('manifest', manifest, 'DATA'), ('version', version, 'DATA')],
*built_executables,
**dict(strip=True,
upx=False,
excludes=excludes,
name='dist'))
os.chdir(os.path.join(HOMEPATH, 'calibre', 'dist'))
for folder in EXTRAS:
subprocess.check_call('cp -rf %%s .'%%folder, shell=True)
print 'Building tarball...'
tf = tarfile.open('%(tarfile)s', 'w:bz2')
for f in os.listdir('.'):
tf.add(f)
"""%dict(home='/mnt/hgfs/giskard/', tarfile=tbz2, project=PROJECT)
os.chdir(os.path.expanduser('~/build/pyinstaller'))
open('calibre/calibre.spec', 'wb').write(SPEC)
try:
subprocess.check_call(('/usr/bin/python', '-O', 'Build.py', 'calibre/calibre.spec'))
finally:
os.chdir(cwd)
return os.path.basename(tbz2)
def build_linux():
installer = installer_name('tar.bz2')
vm = '/vmware/linux/libprs500-gentoo.vmx'
vmware = ('vmware', '-q', '-x', '-n', vm)
subprocess.Popen(vmware)
print 'Waiting for linux to boot up...'
time.sleep(75)
check_call('ssh linux make -C /mnt/hgfs/giskard/work/%s all egg linux_binary'%PROJECT)
check_call('ssh linux sudo poweroff')
start_vm(vm, 'linux', BUILD_SCRIPT%('sudo python setup.py develop', 'python','linux_installer.py'))
subprocess.check_call(('scp', 'linux:/tmp/%s'%os.path.basename(installer), 'dist'))
if not os.path.exists(installer):
raise Exception('Failed to build installer '+installer)
subprocess.Popen(('ssh', 'linux', 'sudo', '/sbin/poweroff'))
return os.path.basename(installer)
def build_installers():
return build_linux(), build_windows(), build_osx()
@ -267,18 +140,14 @@ def upload_user_manual():
finally:
os.chdir(cwd)
def build_tarball():
cwd = os.getcwd()
def build_src_tarball():
check_call('bzr export dist/calibre-%s.tar.bz2'%__version__)
def upload_tarball():
def upload_src_tarball():
check_call('ssh divok rm -f %s/calibre-\*.tar.bz2'%DOWNLOADS)
check_call('scp dist/calibre-*.tar.bz2 divok:%s/'%DOWNLOADS)
def main():
upload = len(sys.argv) < 2
def stage_one():
shutil.rmtree('build')
os.mkdir('build')
shutil.rmtree('docs')
@ -288,17 +157,32 @@ def main():
check_call('make', shell=True)
tag_release()
upload_demo()
def stage_two():
subprocess.check_call('rm -rf dist/*', shell=True)
build_installers()
build_tarball()
if upload:
build_src_tarball()
def stage_three():
print 'Uploading installers...'
upload_installers()
print 'Uploading to PyPI'
upload_tarball()
upload_src_tarball()
upload_docs()
upload_user_manual()
check_call('python setup.py register bdist_egg --exclude-source-files upload')
check_call('''rm -rf dist/* build/*''')
def main(args=sys.argv):
print 'Starting stage one...'
stage_one()
print 'Starting stage two...'
stage_two()
print 'Starting stage three...'
stage_three()
print 'Finished'
return 0
if __name__ == '__main__':
main()
sys.exit(main())