diff --git a/pyqtdistutils.py b/pyqtdistutils.py index 2291efba01..252968fb60 100644 --- a/pyqtdistutils.py +++ b/pyqtdistutils.py @@ -10,7 +10,7 @@ from distutils.core import Extension from distutils.command.build_ext import build_ext as _build_ext from distutils.dep_util import newer_group from distutils import log - + import sipconfig, os, sys, string, glob, shutil from PyQt4 import pyqtconfig iswindows = 'win32' in sys.platform @@ -22,7 +22,7 @@ def replace_suffix(path, new_suffix): return os.path.splitext(path)[0] + new_suffix class PyQtExtension(Extension): - + def __init__(self, name, sources, sip_sources, **kw): ''' :param sources: Qt .cpp and .h files needed for this extension @@ -32,16 +32,16 @@ class PyQtExtension(Extension): self.module_makefile = pyqtconfig.QtGuiModuleMakefile self.sip_sources = map(lambda x: x.replace('/', os.sep), sip_sources) Extension.__init__(self, name, sources, **kw) - + class build_ext(_build_ext): - + def make(self, makefile): make = 'make' if iswindows: make = 'mingw32-make' self.spawn([make, '-f', makefile]) - + def build_qt_objects(self, ext, bdir): if not iswindows: bdir = os.path.join(bdir, 'qt') @@ -53,7 +53,7 @@ class build_ext(_build_ext): try: headers = set([f for f in sources if f.endswith('.h')]) sources = set(sources) - headers - name = ext.name.rpartition('.')[-1] + name = ext.name.rpartition('.')[-1] pro = '''\ TARGET = %s TEMPLATE = lib @@ -69,7 +69,7 @@ CONFIG += x86 ppc return map(os.path.abspath, glob.glob(pat)) finally: os.chdir(cwd) - + def build_sbf(self, sip, sbf, bdir): sip_bin = self.sipcfg.sip_bin self.spawn([sip_bin, @@ -78,10 +78,10 @@ CONFIG += x86 ppc '-I', self.pyqtcfg.pyqt_sip_dir, ] + self.pyqtcfg.pyqt_sip_flags.split()+ [sip]) - + def build_pyqt(self, bdir, sbf, ext, qtobjs, headers): makefile = ext.module_makefile(configuration=self.pyqtcfg, - build_file=sbf, dir=bdir, + build_file=sbf, dir=bdir, makefile='Makefile.pyqt', universal=OSX_SDK, qt=1) if 'win32' in sys.platform: @@ -95,14 +95,14 @@ CONFIG += x86 ppc self.make('Makefile.pyqt') finally: os.chdir(cwd) - - - + + + def build_extension(self, ext): self.inplace = True # Causes extensions to be built in the source tree if not isinstance(ext, PyQtExtension): return _build_ext.build_extension(self, ext) - + fullname = self.get_ext_fullname(ext.name) if self.inplace: # ignore build-lib -- put the compiled extension into @@ -122,20 +122,20 @@ CONFIG += x86 ppc bdir = os.path.abspath(os.path.join(self.build_temp, fullname)) if not os.path.exists(bdir): os.makedirs(bdir) - ext.sources = map(os.path.abspath, ext.sources) + ext.sources2 = map(os.path.abspath, ext.sources) qt_dir = 'qt\\release' if iswindows else 'qt' objects = set(map(lambda x: os.path.join(bdir, qt_dir, replace_suffix(os.path.basename(x), '.o')), - [s for s in ext.sources if not s.endswith('.h')])) + [s for s in ext.sources2 if not s.endswith('.h')])) newer = False for object in objects: - if newer_group(ext.sources, object, missing='newer'): + if newer_group(ext.sources2, object, missing='newer'): newer = True break - headers = [f for f in ext.sources if f.endswith('.h')] + headers = [f for f in ext.sources2 if f.endswith('.h')] if self.force or newer: log.info('building \'%s\' extension', ext.name) objects = self.build_qt_objects(ext, bdir) - + self.sipcfg = sipconfig.Configuration() self.pyqtcfg = pyqtconfig.Configuration() sbf_sources = [] @@ -148,19 +148,19 @@ CONFIG += x86 ppc generated_sources = [] for sbf in sbf_sources: generated_sources += self.get_sip_output_list(sbf, bdir) - + depends = generated_sources + list(objects) mod = os.path.join(bdir, os.path.basename(ext_filename)) - + if self.force or newer_group(depends, mod, 'newer'): self.build_pyqt(bdir, sbf_sources[0], ext, list(objects), headers) - + if self.force or newer_group([mod], ext_filename, 'newer'): if os.path.exists(ext_filename): os.unlink(ext_filename) shutil.copyfile(mod, ext_filename) shutil.copymode(mod, ext_filename) - + def get_sip_output_list(self, sbf, bdir): """ Parse the sbf file specified to extract the name of the generated source @@ -175,7 +175,7 @@ CONFIG += x86 ppc return out raise RuntimeError, "cannot parse SIP-generated '%s'" % sbf - + def run_sip(self, sip_files): sip_bin = self.sipcfg.sip_bin sip_sources = [i[0] for i in sip_files] @@ -191,6 +191,5 @@ CONFIG += x86 ppc ] + self.pyqtcfg.pyqt_sip_flags.split()+ [sip]) generated_sources += self.get_sip_output_list(sbf) - return generated_sources - - \ No newline at end of file + return generated_sources + diff --git a/resources.py b/resources.py deleted file mode 100644 index 9ce1525ec5..0000000000 --- a/resources.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python - -__license__ = 'GPL v3' -__copyright__ = '2008, Kovid Goyal ' -''' -Compile resource files. -''' -import os, sys, glob -sys.path.insert(1, os.path.join(os.getcwd(), 'src')) - -RESOURCES = dict( - opf_template = '%p/ebooks/metadata/opf.xml', - ncx_template = '%p/ebooks/metadata/ncx.xml', - fb2_xsl = '%p/ebooks/lrf/fb2/fb2.xsl', - metadata_sqlite = '%p/library/metadata_sqlite.sql', - ) - -def main(args=sys.argv): - data = '' - for key, value in RESOURCES.items(): - path = value.replace('%p', 'src'+os.sep+'calibre') - bytes = repr(open(path, 'rb').read()) - data += key + ' = ' + bytes + '\n\n' - - translations_found = False - for TPATH in ('/usr/share/qt4/translations', '/usr/lib/qt4/translations'): - if os.path.exists(TPATH): - files = glob.glob(TPATH + '/qt_??.qm') - - for f in files: - key = os.path.basename(f).partition('.')[0] - bytes = repr(open(f, 'rb').read()) - data += key + ' = ' + bytes + '\n\n' - translations_found = True - break - if not translations_found: - print 'WARNING: Could not find Qt transations' - - dest = os.path.abspath(os.path.join('src', 'calibre', 'resources.py')) - print 'Writing resources to', dest - open(dest, 'wb').write(data) - return 0 - -if __name__ == '__main__': - sys.exit(main()) diff --git a/setup.py b/setup.py index 0292aba9c0..993d7c9b07 100644 --- a/setup.py +++ b/setup.py @@ -1,8 +1,8 @@ -#!/usr/bin/env python +from __future__ import with_statement __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' -import sys, re, os, shutil +import sys, re, os, shutil, cStringIO, tempfile, subprocess sys.path.append('src') iswindows = re.search('win(32|64)', sys.platform) isosx = 'darwin' in sys.platform @@ -48,66 +48,291 @@ main_functions = { if __name__ == '__main__': from setuptools import setup, find_packages, Extension from distutils.command.build import build as _build - from distutils.core import Command + from distutils.core import Command as _Command from pyqtdistutils import PyQtExtension, build_ext import subprocess, glob - class pot(Command): - user_options = [] - def initialize_options(self): pass - def finalize_options(self): pass - - def run(self): - from calibre.translations import create_pot - create_pot() - - def build_manual(): - cwd = os.path.abspath(os.getcwd()) - os.chdir(os.path.join('src', 'calibre', 'manual')) - try: - for d in ('.build', 'cli'): - if os.path.exists(d): - shutil.rmtree(d) - os.makedirs(d) - if not os.path.exists('.build'+os.sep+'html'): - os.makedirs('.build'+os.sep+'html') - subprocess.check_call(['sphinx-build', '-b', 'custom', '-d', - '.build/doctrees', '.', '.build/html']) - finally: - os.chdir(cwd) + def newer(targets, sources): + ''' + Return True is sources is newer that targets or if targets + does not exist. + ''' + for f in targets: + if not os.path.exists(f): + return True + ttimes = map(lambda x: os.stat(x).st_mtime, targets) + stimes = map(lambda x: os.stat(x).st_mtime, sources) + newest_source, oldest_target = max(stimes), min(ttimes) + return newest_source > oldest_target - class manual(Command): + class Command(_Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass + + class pot(Command): + ''' Create the .pot template for all translatable strings ''' + + PATH = os.path.join('src', APPNAME, 'translations') + + def source_files(self): + ans = [] + for root, dirs, files in os.walk(os.path.dirname(self.PATH)): + for name in files: + if name.endswith('.py'): + ans.append(os.path.abspath(os.path.join(root, name))) + return ans + def run(self): - build_manual() + sys.path.insert(0, os.path.abspath(self.PATH)) + try: + from pygettext import main as pygettext + files = self.source_files() + buf = cStringIO.StringIO() + print 'Creating translations template' + tempdir = tempfile.mkdtemp() + pygettext(buf, ['-p', tempdir]+files) + src = buf.getvalue() + pot = os.path.join(tempdir, 'calibre.pot') + f = open(pot, 'wb') + f.write(src) + f.close() + print 'Translations template:', pot + return pot + finally: + sys.path.remove(os.path.abspath(self.PATH)) + class manual(Command): + ''' Build the User Manual ''' + def run(self): + cwd = os.path.abspath(os.getcwd()) + os.chdir(os.path.join('src', 'calibre', 'manual')) + try: + for d in ('.build', 'cli'): + if os.path.exists(d): + shutil.rmtree(d) + os.makedirs(d) + if not os.path.exists('.build'+os.sep+'html'): + os.makedirs('.build'+os.sep+'html') + subprocess.check_call(['sphinx-build', '-b', 'custom', '-d', + '.build/doctrees', '.', '.build/html']) + finally: + os.chdir(cwd) + + @classmethod + def clean(cls): + path = os.path.join('src', 'calibre', 'manual', '.build') + if os.path.exists(path): + shutil.rmtree(path) + + class resources(Command): + ''' + Compile various resource files used in calibre. + ''' + + RESOURCES = dict( + opf_template = 'ebooks/metadata/opf.xml', + ncx_template = 'ebooks/metadata/ncx.xml', + fb2_xsl = 'ebooks/lrf/fb2/fb2.xsl', + metadata_sqlite = 'library/metadata_sqlite.sql', + ) + + DEST = os.path.join('src', APPNAME, 'resources.py') + + def get_qt_translations(self): + data = {} + translations_found = False + for TPATH in ('/usr/share/qt4/translations', '/usr/lib/qt4/translations'): + if os.path.exists(TPATH): + files = glob.glob(TPATH + '/qt_??.qm') + for f in files: + key = os.path.basename(f).partition('.')[0] + data[key] = f + translations_found = True + break + if not translations_found: + print 'WARNING: Could not find Qt transations' + return data + + def run(self): + data, dest, RESOURCES = {}, self.DEST, self.RESOURCES + for key in RESOURCES: + path = RESOURCES[key] + if not os.path.isabs(path): + RESOURCES[key] = os.path.join('src', APPNAME, path) + translations = self.get_qt_translations() + RESOURCES.update(translations) + if newer([dest], RESOURCES.values()): + print 'Compiling resources...' + with open(dest, 'wb') as f: + for key in RESOURCES: + data = open(RESOURCES[key], 'rb').read() + f.write(key + ' = ' + repr(data)+'\n\n') + else: + print 'Resources are up to date' + + @classmethod + def clean(cls): + path = cls.DEST + for path in glob.glob(path+'*'): + if os.path.exists(path): + os.remove(path) + + class translations(Command): + ''' + Compile the translations + ''' + PATH = os.path.join('src', APPNAME, 'translations') + DEST = os.path.join(PATH, 'compiled.py') + + def run(self): + sys.path.insert(0, os.path.abspath(self.PATH)) + try: + files = glob.glob(os.path.join(self.PATH, '*.po')) + if newer([self.DEST], files): + from msgfmt import main as msgfmt + translations = {} + print 'Compiling translations...' + for po in files: + lang = os.path.basename(po).partition('.')[0] + buf = cStringIO.StringIO() + print 'Compiling', lang + msgfmt(buf, [po]) + translations[lang] = buf.getvalue() + open(self.DEST, 'wb').write('translations = '+repr(translations)) + else: + print 'Translations up to date' + finally: + sys.path.remove(os.path.abspath(self.PATH)) + + + @classmethod + def clean(cls): + path = cls.DEST + if os.path.exists(path): + os.remove(path) + + + class gui(Command): + ''' + Compile all GUI forms and image related resources. + ''' + PATH = os.path.join('src', APPNAME, 'gui2') + IMAGES_DEST = os.path.join(PATH, 'images_rc.py') + + @classmethod + def find_forms(cls): + forms = [] + for root, dirs, files in os.walk(cls.PATH): + for name in files: + if name.endswith('.ui'): + forms.append(os.path.abspath(os.path.join(root, name))) + + return forms + + @classmethod + def form_to_compiled_form(cls, form): + return form.rpartition('.')[0]+'_ui.py' + + def run(self): + self.build_forms() + self.build_images() + + def build_images(self): + cwd, images = os.getcwd(), os.path.basename(self.IMAGES_DEST) + try: + os.chdir(self.PATH) + sources, files = [], [] + for root, dirs, files in os.walk('images'): + for name in files: + sources.append(os.path.join(root, name)) + if newer([images], sources): + print 'Compiling images...' + for s in sources: + alias = ' alias="library"' if s.endswith('images'+os.sep+'library.png') else '' + files.append('%s'%(alias, s)) + manifest = '\n\n%s\n\n'%'\n'.join(files) + with open('images.qrc', 'wb') as f: + f.write(manifest) + subprocess.check_call(['pyrcc4', '-o', images, 'images.qrc']) + os.remove('images.qrc') + else: + print 'Images are up to date' + finally: + os.chdir(cwd) + + + def build_forms(self): + from PyQt4.uic import compileUi + forms = self.find_forms() + for form in forms: + compiled_form = self.form_to_compiled_form(form) + if not os.path.exists(compiled_form) or os.stat(form).st_mtime > os.stat(compiled_form).st_mtime: + print 'Compiling form', form + buf = cStringIO.StringIO() + compileUi(form, buf) + dat = buf.getvalue() + dat = dat.replace('__appname__', APPNAME) + dat = dat.replace('import images_rc', 'from calibre.gui2 import images_rc') + dat = dat.replace('from library import', 'from calibre.gui2.library import') + dat = dat.replace('from widgets import', 'from calibre.gui2.widgets import') + dat = re.compile(r'QtGui.QApplication.translate\(.+?,\s+"(.+?)(?" ''' Various run time constants. diff --git a/src/calibre/ebooks/lrf/pylrs/pylrs.py b/src/calibre/ebooks/lrf/pylrs/pylrs.py index a8cbb6fb1c..9fcf0ef624 100644 --- a/src/calibre/ebooks/lrf/pylrs/pylrs.py +++ b/src/calibre/ebooks/lrf/pylrs/pylrs.py @@ -603,7 +603,7 @@ class Book(Delegator): def renderLrs(self, lrsFile, encoding="UTF-8"): - if isinstance(lrsFile, basestring): + if isinstance(lrsFile, basestring): lrsFile = codecs.open(lrsFile, "wb", encoding=encoding) self.render(lrsFile, outputEncodingName=encoding) lrsFile.close() diff --git a/src/calibre/gui2/make.py b/src/calibre/gui2/make.py deleted file mode 100644 index fea040ca71..0000000000 --- a/src/calibre/gui2/make.py +++ /dev/null @@ -1,116 +0,0 @@ -__license__ = 'GPL v3' -__copyright__ = '2008, Kovid Goyal ' -''' -Manage the PyQt build system pyrcc4, pylupdate4, lrelease and friends. -''' - -import sys, os, subprocess, cStringIO, compiler, re -from functools import partial - -from PyQt4.uic import compileUi - -check_call = partial(subprocess.check_call, shell=True) -sys.path.insert(1, os.path.abspath('..%s..'%os.sep)) - -from calibre import __appname__ -from calibre.path import path - -def find_forms(): - forms = [] - for root, dirs, files in os.walk('.'): - for name in files: - if name.endswith('.ui'): - forms.append(os.path.abspath(os.path.join(root, name))) - - return forms - -def form_to_compiled_form(form): - return form.rpartition('.')[0]+'_ui.py' - -def build_forms(forms): - for form in forms: - compiled_form = form_to_compiled_form(form) - if not os.path.exists(compiled_form) or os.stat(form).st_mtime > os.stat(compiled_form).st_mtime: - print 'Compiling form', form - buf = cStringIO.StringIO() - compileUi(form, buf) - dat = buf.getvalue() - dat = dat.replace('__appname__', __appname__) - dat = dat.replace('import images_rc', 'from calibre.gui2 import images_rc') - dat = dat.replace('from library import', 'from calibre.gui2.library import') - dat = dat.replace('from widgets import', 'from calibre.gui2.widgets import') - dat = re.compile(r'QtGui.QApplication.translate\(.+?,\s+"(.+?)(? images.mtime: - print 'Compiling images...' - files = [] - for x in p.walk(): - if '.svn' in x or '.bzr' in x or x.isdir(): - continue - alias = ' alias="library"' if x == p/'library.png' else '' - files.append('%s'%(alias, x)) - qrc = '\n\n%s\n\n'%'\n'.join(files) - f = open('images.qrc', 'wb') - f.write(qrc) - f.close() - check_call(' '.join(['pyrcc4', '-o', images, 'images.qrc'])) - compiler.compileFile(images) - os.utime(images, None) - os.utime(images, None) - print 'Size of images:', '%.2f MB'%(path(images+'c').size/(1024*1024.)) - - -def build(forms): - build_forms(forms) - build_images() - -def clean(forms): - for form in forms: - compiled_form = form_to_compiled_form(form) - if os.path.exists(compiled_form): - print 'Removing compiled form', compiled_form - os.unlink(compiled_form) - print 'Removing compiled images' - os.unlink('images_rc.py') - os.unlink('images_rc.pyc') - -def main(args=sys.argv): - - if not os.getcwd().endswith('gui2'): - raise Exception('Must be run from the gui2 directory') - - forms = find_forms() - if len(args) == 1: - args.append('all') - - if args[1] == 'all': - build(forms) - elif args[1] == 'clean': - clean(forms) - elif args[1] == 'test': - build(forms) - print 'Running main.py' - subprocess.call('python main.py', shell=True) - else: - print 'Usage: %s [all|clean|test]'%(args[0]) - return 1 - - return 0 - -if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py index 684c308a2d..f793a29dc3 100644 --- a/src/calibre/library/database2.py +++ b/src/calibre/library/database2.py @@ -246,11 +246,20 @@ class LibraryDatabase2(LibraryDatabase): spath = os.path.join(self.library_path, *current_path.split('/')) if current_path and os.path.exists(spath): for f in os.listdir(spath): - copyfile(os.path.join(spath, f), os.path.join(tpath, f)) + try: + copyfile(os.path.join(spath, f), os.path.join(tpath, f)) + except OSError, err: + if err.errno == 78: # Happens if database is mounted via sshfs + shutil.copyfile(os.path.join(spath, f), os.path.join(tpath, f)) + else: + raise self.conn.execute('UPDATE books SET path=? WHERE id=?', (path, id)) self.conn.commit() if current_path and os.path.exists(spath): shutil.rmtree(spath) + parent = os.path.dirname(spath) + if len(os.listdir(parent)) == 0: + shutil.rmtree(parent) def cover(self, index, index_is_id=False, as_file=False, as_image=False): ''' @@ -495,6 +504,7 @@ class LibraryDatabase2(LibraryDatabase): QCoreApplication.processEvents() db.conn.row_factory = lambda cursor, row : tuple(row) books = db.conn.execute('SELECT id, title, sort, timestamp, uri, series_index, author_sort, isbn FROM books ORDER BY id ASC').fetchall() + progress.setAutoReset(False) progress.setRange(0, len(books)) for book in books: @@ -533,4 +543,5 @@ books_series_link feeds self.conn.commit() progress.setLabelText(_('Compacting database')) self.vacuum() + progress.reset() diff --git a/src/calibre/startup.py b/src/calibre/startup.py index 2f4467b0f8..e46bc1acb9 100644 --- a/src/calibre/startup.py +++ b/src/calibre/startup.py @@ -12,7 +12,7 @@ from gettext import GNUTranslations # Default translation is NOOP import __builtin__ __builtin__.__dict__['_'] = lambda s: s - + from calibre.constants import iswindows, isosx, islinux, isfrozen,\ preferred_encoding from calibre.translations.msgfmt import make @@ -22,7 +22,7 @@ if not _run_once: _run_once = True ################################################################################ # Setup translations - + def get_lang(): lang = locale.getdefaultlocale()[0] if lang is None and os.environ.has_key('LANG'): # Needed for OS X @@ -35,7 +35,7 @@ if not _run_once: if match: lang = match.group() return lang - + def set_translator(): # To test different translations invoke as # LC_ALL=de_DE.utf8 program @@ -43,7 +43,7 @@ if not _run_once: from calibre.translations.compiled import translations except: return - lang = get_lang() + lang = get_lang() if lang: buf = None if os.access(lang+'.po', os.R_OK): @@ -55,9 +55,9 @@ if not _run_once: if buf is not None: t = GNUTranslations(buf) t.install(unicode=True) - + set_translator() - + ################################################################################ # Initialize locale try: @@ -69,37 +69,42 @@ if not _run_once: locale.setlocale(dl[0]) except: pass - + ################################################################################ # Load plugins - if isfrozen: - if iswindows: - plugin_path = os.path.join(os.path.dirname(sys.executable), 'plugins') - sys.path.insert(1, os.path.dirname(sys.executable)) - elif isosx: - plugin_path = os.path.join(getattr(sys, 'frameworks_dir'), 'plugins') - elif islinux: - plugin_path = os.path.join(getattr(sys, 'frozen_path'), 'plugins') - sys.path.insert(0, plugin_path) - else: - import pkg_resources - plugins = getattr(pkg_resources, 'resource_filename')('calibre', 'plugins') - sys.path.insert(0, plugins) - - plugins = {} - for plugin in ['pictureflow', 'lzx', 'msdes'] + \ - (['winutil'] if iswindows else []) + \ - (['usbobserver'] if isosx else []): - try: - p, err = __import__(plugin), '' - except Exception, err: - p = None - err = str(err) - plugins[plugin] = (p, err) - + def load_plugins(): + plugins = {} + if isfrozen: + if iswindows: + plugin_path = os.path.join(os.path.dirname(sys.executable), 'plugins') + sys.path.insert(1, os.path.dirname(sys.executable)) + elif isosx: + plugin_path = os.path.join(getattr(sys, 'frameworks_dir'), 'plugins') + elif islinux: + plugin_path = os.path.join(getattr(sys, 'frozen_path'), 'plugins') + sys.path.insert(0, plugin_path) + else: + import pkg_resources + plugin_path = getattr(pkg_resources, 'resource_filename')('calibre', 'plugins') + sys.path.insert(0, plugin_path) + + for plugin in ['pictureflow', 'lzx', 'msdes'] + \ + (['winutil'] if iswindows else []) + \ + (['usbobserver'] if isosx else []): + try: + p, err = __import__(plugin), '' + except Exception, err: + p = None + err = str(err) + plugins[plugin] = (p, err) + return plugins + + plugins = load_plugins() + + ################################################################################ # Improve builtin path functions to handle unicode sensibly - + _abspath = os.path.abspath def my_abspath(path, encoding=sys.getfilesystemencoding()): ''' @@ -115,7 +120,7 @@ if not _run_once: if to_unicode: res = res.decode(encoding) return res - + os.path.abspath = my_abspath _join = os.path.join def my_join(a, *p): @@ -127,15 +132,15 @@ if not _run_once: _unicode = True break p = [i.encode(encoding) if isinstance(i, unicode) else i for i in p] - + res = _join(*p) if _unicode: res = res.decode(encoding) return res - + os.path.join = my_join - - + + ################################################################################ # Platform specific modules winutil = winutilerror = None @@ -145,10 +150,9 @@ if not _run_once: raise RuntimeError('Failed to load the winutil plugin: %s'%winutilerror) if len(sys.argv) > 1: sys.argv[1:] = winutil.argv()[1-len(sys.argv):] - + ################################################################################ # Convert command line arguments to unicode for i in range(1, len(sys.argv)): if not isinstance(sys.argv[i], unicode): sys.argv[i] = sys.argv[i].decode(preferred_encoding, 'replace') - \ No newline at end of file diff --git a/src/calibre/translations/__init__.py b/src/calibre/translations/__init__.py index 9aca9e9fca..569adcac5a 100644 --- a/src/calibre/translations/__init__.py +++ b/src/calibre/translations/__init__.py @@ -3,102 +3,3 @@ __copyright__ = '2008, Kovid Goyal ' ''' Manage translation of user visible strings. ''' -import sys, os, cStringIO, tempfile, subprocess, functools, tarfile, re, time, \ - glob, urllib2, shutil -check_call = functools.partial(subprocess.check_call, shell=True) - -try: - from calibre.translations.pygettext import main as pygettext - from calibre.translations.msgfmt import main as msgfmt -except ImportError: - cwd = os.getcwd() - sys.path.insert(0, os.path.dirname(os.path.dirname(cwd))) - from calibre.translations.pygettext import main as pygettext - from calibre.translations.msgfmt import main as msgfmt - - -def source_files(): - ans = [] - for root, dirs, files in os.walk(os.path.dirname(os.getcwdu())): - for name in files: - if name.endswith('.py'): - ans.append(os.path.abspath(os.path.join(root, name))) - return ans - - -def create_pot(): - files = source_files() - buf = cStringIO.StringIO() - print 'Creating translations template' - tempdir = tempfile.mkdtemp() - pygettext(buf, ['-p', tempdir]+files) - src = buf.getvalue() - pot = os.path.join(tempdir, 'calibre.pot') - f = open(pot, 'wb') - f.write(src) - f.close() - print 'Translations template:', pot - return pot - - -def compile_translations(): - translations = {} - print 'Compiling translations...' - for po in glob.glob('*.po'): - lang = os.path.basename(po).partition('.')[0] - buf = cStringIO.StringIO() - print 'Compiling', lang - msgfmt(buf, [po]) - translations[lang] = buf.getvalue() - open('compiled.py', 'wb').write('translations = '+repr(translations)) - -def import_from_launchpad(url): - f = open('/tmp/launchpad_export.tar.gz', 'wb') - shutil.copyfileobj(urllib2.urlopen(url), f) - f.close() - tf = tarfile.open('/tmp/launchpad_export.tar.gz', 'r:gz') - next = tf.next() - while next is not None: - if next.isfile() and next.name.endswith('.po'): - try: - po = re.search(r'-([a-z]{2,3}\.po)', next.name).group(1) - except: - next = tf.next() - continue - out = os.path.abspath(os.path.join('.', os.path.basename(po))) - print 'Updating', '%6s'%po, '-->', out - open(out, 'wb').write(tf.extractfile(next).read()) - next = tf.next() - - check_for_critical_bugs() - return 0 - -def check_for_critical_bugs(): - if os.path.exists('.errors'): - shutil.rmtree('.errors') - pofilter = ('pofilter', '-i', '.', '-o', '.errors', - '-t', 'accelerators', '-t', 'escapes', '-t', 'variables', - '-t', 'xmltags') - subprocess.check_call(pofilter) - errs = os.listdir('.errors') - if errs: - print 'WARNING: Translation errors detected' - print 'See the .errors directory and http://translate.sourceforge.net/wiki/toolkit/using_pofilter' - - -def main(args=sys.argv): - if len(args) > 1: - if args[1] == 'pot': - create_pot() - else: - import_from_launchpad(args[1]) - else: - compile_translations() - return 0 - -if __name__ == '__main__': - cwd = os.getcwd() - sys.path.insert(0, os.path.dirname(os.path.dirname(cwd))) - - sys.exit(main()) - diff --git a/src/calibre/utils/config.py b/src/calibre/utils/config.py index 5ec24947dc..1ae4afc15c 100644 --- a/src/calibre/utils/config.py +++ b/src/calibre/utils/config.py @@ -284,6 +284,8 @@ class OptionSet(object): def parse_string(self, src): options = {'cPickle':cPickle} + if not isinstance(src, unicode): + src = src.decode('utf-8') if src is not None: exec src in options opts = OptionValues() @@ -352,7 +354,7 @@ class Config(ConfigInterface): if os.path.exists(self.config_file_path): try: with ExclusiveFile(self.config_file_path) as f: - src = f.read() + src = f.read().decode('utf-8') except LockError: raise IOError('Could not lock config file: %s'%self.config_file_path) return self.option_set.parse_string(src) @@ -362,7 +364,7 @@ class Config(ConfigInterface): return '' try: with ExclusiveFile(self.config_file_path) as f: - return f.read() + return f.read().decode('utf-8') except LockError: raise IOError('Could not lock config file: %s'%self.config_file_path) @@ -380,6 +382,8 @@ class Config(ConfigInterface): src = self.option_set.serialize(opts)+ '\n\n' + footer + '\n' f.seek(0) f.truncate() + if isinstance(src, unicode): + src = src.encode('utf-8') f.write(src) except LockError: raise IOError('Could not lock config file: %s'%self.config_file_path) diff --git a/src/calibre/utils/windows/winutil.c b/src/calibre/utils/windows/winutil.c index 3419c8d2dc..85f019f8c4 100644 --- a/src/calibre/utils/windows/winutil.c +++ b/src/calibre/utils/windows/winutil.c @@ -118,7 +118,7 @@ winutil_argv(PyObject *self, PyObject *args) { LPSTR buf; int argc, i, bytes; if (!PyArg_ParseTuple(args, "")) return NULL; - _argv = CommandLineToArgvW(GetCommandLine(), &argc); + _argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (_argv == NULL) { PyErr_NoMemory(); return NULL; } argv = PyList_New(argc); if (argv != NULL) { diff --git a/upload.py b/upload.py index a653b7e891..50bcf7166d 100644 --- a/upload.py +++ b/upload.py @@ -27,6 +27,7 @@ TXT2LRF = "src/calibre/ebooks/lrf/txt/demo" MOBILEREAD = 'ftp://dev.mobileread.com/calibre/' BUILD_SCRIPT ='''\ #!/bin/bash +export CALIBRE_BUILDBOT=1 cd ~/build && \ rsync -avz --exclude src/calibre/plugins --exclude calibre/src/calibre.egg-info --exclude docs --exclude .bzr --exclude .build --exclude build --exclude dist --exclude "*.pyc" --exclude "*.pyo" rsync://%(host)s/work/%(project)s . && \ cd %(project)s && \