diff --git a/installer/osx/freeze.py b/installer/osx/freeze.py index ff1684bb04..c1e458caf8 100644 --- a/installer/osx/freeze.py +++ b/installer/osx/freeze.py @@ -57,7 +57,7 @@ r''' def _check_symlinks_prescript(): import os, tempfile, traceback, sys from Authorization import Authorization, kAuthorizationFlagDestroyRights - + AUTHTOOL="""#!%(sp)s import os scripts = %(sp)s @@ -71,13 +71,13 @@ for s, l in zip(scripts, links): os.symlink(s, l) os.umask(omask) """ - + dest_path = %(dest_path)s resources_path = os.environ['RESOURCEPATH'] - scripts = %(scripts)s + scripts = %(scripts)s links = [os.path.join(dest_path, i) for i in scripts] scripts = [os.path.join(resources_path, 'loaders', i) for i in scripts] - + bad = False for s, l in zip(scripts, links): if os.path.exists(l) and os.path.exists(os.path.realpath(l)): @@ -111,22 +111,22 @@ _check_symlinks_prescript() packages=self.packages, excludes=self.excludes, debug=debug) - + @classmethod - def makedmg(cls, d, volname, - destdir='dist', + def makedmg(cls, d, volname, + destdir='dist', internet_enable=True, format='UDBZ'): ''' Copy a directory d into a dmg named volname ''' dmg = os.path.join(destdir, volname+'.dmg') if os.path.exists(dmg): os.unlink(dmg) - subprocess.check_call(['/usr/bin/hdiutil', 'create', '-srcfolder', os.path.abspath(d), + subprocess.check_call(['/usr/bin/hdiutil', 'create', '-srcfolder', os.path.abspath(d), '-volname', volname, '-format', format, dmg]) if internet_enable: subprocess.check_call(['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg]) return dmg - + @classmethod def qt_dependencies(cls, path): pipe = subprocess.Popen('/usr/bin/otool -L '+path, shell=True, stdout=subprocess.PIPE).stdout @@ -134,12 +134,12 @@ _check_symlinks_prescript() for l in pipe.readlines(): match = re.search(r'(.*)\(', l) if not match: - continue + continue lib = match.group(1).strip() if lib.startswith(BuildAPP.QT_PREFIX): deps.append(lib) return deps - + @classmethod def fix_qt_dependencies(cls, path, deps): fp = '@executable_path/../Frameworks/' @@ -155,8 +155,8 @@ _check_symlinks_prescript() newpath = fp + '%s.framework/Versions/Current/%s'%(module, module) cmd = ' '.join(['/usr/bin/install_name_tool', '-change', dep, newpath, path]) subprocess.check_call(cmd, shell=True) - - + + def add_qt_plugins(self): macos_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'MacOS') for root, dirs, files in os.walk(BuildAPP.QT_PREFIX+'/plugins'): @@ -172,14 +172,14 @@ _check_symlinks_prescript() shutil.copymode(path, target) deps = BuildAPP.qt_dependencies(target) BuildAPP.fix_qt_dependencies(target, deps) - - + + #deps = BuildAPP.qt_dependencies(path) - + def fix_python_dependencies(self, files): for f in files: subprocess.check_call(['/usr/bin/install_name_tool', '-change', '/Library/Frameworks/Python.framework/Versions/2.6/Python', '@executable_path/../Frameworks/Python.framework/Versions/2.6/Python', f]) - + def fix_misc_dependencies(self, files): for path in files: frameworks_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'Frameworks') @@ -195,15 +195,15 @@ _check_symlinks_prescript() if os.path.exists(bundle): subprocess.check_call(['/usr/bin/install_name_tool', '-change', dep, '@executable_path/../Frameworks/'+name, path]) - - + + def add_plugins(self): self.add_qt_plugins() frameworks_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'Frameworks') plugins_dir = os.path.join(frameworks_dir, 'plugins') if not os.path.exists(plugins_dir): os.mkdir(plugins_dir) - + maps = {} for f in glob.glob('src/calibre/plugins/*'): tgt = plugins_dir @@ -217,8 +217,8 @@ _check_symlinks_prescript() deps.append(dst) self.fix_python_dependencies(deps) self.fix_misc_dependencies(deps) - - + + def run(self): py2app.run(self) resource_dir = os.path.join(self.dist_dir, @@ -242,8 +242,8 @@ _check_symlinks_prescript() os.chmod(path, stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH|stat.S_IREAD\ |stat.S_IWUSR|stat.S_IROTH|stat.S_IRGRP) self.add_plugins() - - + + print print 'Adding pdftohtml' os.link(os.path.expanduser('~/pdftohtml'), os.path.join(frameworks_dir, 'pdftohtml')) @@ -259,21 +259,21 @@ _check_symlinks_prescript() if os.path.exists(dst): shutil.rmtree(dst) shutil.copytree('/usr/local/etc/fonts', dst, symlinks=False) - + print print 'Adding IPython' dst = os.path.join(resource_dir, 'lib', 'python2.6', 'IPython') if os.path.exists(dst): shutil.rmtree(dst) shutil.copytree(os.path.expanduser('~/build/ipython/IPython'), dst) - - print + + print print 'Adding ImageMagick' dest = os.path.join(frameworks_dir, 'ImageMagick') if os.path.exists(dest): - sutil.rmtree(dest) + shutil.rmtree(dest) shutil.copytree(os.path.expanduser('~/ImageMagick'), dest, True) shutil.copyfile('/usr/local/lib/libpng12.0.dylib', os.path.join(dest, 'lib', 'libpng12.0.dylib')) - + print print 'Installing prescipt' sf = [os.path.basename(s) for s in all_names] @@ -293,13 +293,13 @@ sys.frameworks_dir = os.path.join(os.path.dirname(os.environ['RESOURCEPATH']), ' print >>f, 'import sys, os' f.write(src) f.close() - print + print print 'Adding main scripts to site-packages' f = zipfile.ZipFile(os.path.join(self.dist_dir, APPNAME+'.app', 'Contents', 'Resources', 'lib', 'python'+sys.version[:3], 'site-packages.zip'), 'a', zipfile.ZIP_DEFLATED) for script in scripts['gui']+scripts['console']: f.write(script, script.partition('/')[-1]) f.close() - print + print print 'Creating console.app' contents_dir = os.path.dirname(resource_dir) cc_dir = os.path.join(contents_dir, 'console.app', 'Contents') @@ -312,7 +312,7 @@ sys.frameworks_dir = os.path.join(os.path.dirname(os.environ['RESOURCEPATH']), ' plist['LSUIElement'] = '1' plistlib.writePlist(plist, os.path.join(cc_dir, x)) else: - os.symlink(os.path.join('../..', x), + os.symlink(os.path.join('../..', x), os.path.join(cc_dir, x)) print print 'Building disk image' @@ -343,9 +343,10 @@ def main(): 'calibre.ebooks.lrf.any.*', 'calibre.ebooks.lrf.feeds.*', 'keyword', 'codeop', 'pydoc', 'readline', 'BeautifulSoup', 'calibre.ebooks.lrf.fonts.prs500.*', - 'dateutil', + 'dateutil', 'email.iterators', + 'email.generator', ], - 'packages' : ['PIL', 'Authorization', 'lxml'], + 'packages' : ['PIL', 'Authorization', 'lxml', 'dns'], 'excludes' : ['IPython'], 'plist' : { 'CFBundleGetInfoString' : '''calibre, an E-book management application.''' ''' Visit http://calibre.kovidgoyal.net for details.''', diff --git a/src/calibre/ebooks/metadata/fetch.py b/src/calibre/ebooks/metadata/fetch.py index 682291ae48..57d4368883 100644 --- a/src/calibre/ebooks/metadata/fetch.py +++ b/src/calibre/ebooks/metadata/fetch.py @@ -11,7 +11,7 @@ from calibre.utils.config import OptionParser class FetchGoogle(Thread): name = 'Google Books' - + def __init__(self, title, author, publisher, isbn, verbose): self.title = title self.verbose = verbose @@ -21,17 +21,17 @@ class FetchGoogle(Thread): Thread.__init__(self, None) self.daemon = True self.exception, self.tb = None, None - + def run(self): from calibre.ebooks.metadata.google_books import search try: - self.results = search(self.title, self.author, self.publisher, - self.isbn, max_results=10, + self.results = search(self.title, self.author, self.publisher, + self.isbn, max_results=10, verbose=self.verbose) except Exception, e: self.results = [] self.exception = e - self.tb = traceback.format_exc() + self.tb = traceback.format_exc() class FetchISBNDB(Thread): @@ -46,19 +46,21 @@ class FetchISBNDB(Thread): self.daemon = True self.exception, self.tb = None, None self.key = key - + def run(self): from calibre.ebooks.metadata.isbndb import option_parser, create_books args = ['isbndb'] if self.isbn: args.extend(['--isbn', self.isbn]) - else: + else: if self.title: args.extend(['--title', self.title]) if self.author: args.extend(['--author', self.author]) if self.publisher: args.extend(['--publisher', self.publisher]) + if self.verbose: + args.extend(['--verbose']) args.append(self.key) try: opts, args = option_parser().parse_args(args) @@ -75,7 +77,7 @@ def result_index(source, result): if x.isbn == result.isbn: return i return -1 - + def merge_results(one, two): for x in two: idx = result_index(one, x) @@ -90,42 +92,42 @@ def search(title=None, author=None, publisher=None, isbn=None, isbndb_key=None, isbn is None) fetchers = [FetchGoogle(title, author, publisher, isbn, verbose)] if isbndb_key: - fetchers.append(FetchISBNDB(title, author, publisher, isbn, verbose, + fetchers.append(FetchISBNDB(title, author, publisher, isbn, verbose, isbndb_key)) - - + + for fetcher in fetchers: fetcher.start() for fetcher in fetchers: fetcher.join() for fetcher in fetchers[1:]: merge_results(fetchers[0].results, fetcher.results) - + results = sorted(fetchers[0].results, cmp=lambda x, y : cmp( (x.comments.strip() if x.comments else ''), (y.comments.strip() if y.comments else '') ), reverse=True) - + return results, [(x.name, x.exception, x.tb) for x in fetchers] - + def option_parser(): parser = OptionParser(textwrap.dedent( '''\ %prog [options] - - Fetch book metadata from online sources. You must specify at least one - of title, author, publisher or ISBN. If you specify ISBN, the others - are ignored. + + Fetch book metadata from online sources. You must specify at least one + of title, author, publisher or ISBN. If you specify ISBN, the others + are ignored. ''' )) parser.add_option('-t', '--title', help='Book title') parser.add_option('-a', '--author', help='Book author(s)') parser.add_option('-p', '--publisher', help='Book publisher') parser.add_option('-i', '--isbn', help='Book ISBN') - parser.add_option('-m', '--max-results', default=10, + parser.add_option('-m', '--max-results', default=10, help='Maximum number of results to fetch') - parser.add_option('-k', '--isbndb-key', + parser.add_option('-k', '--isbndb-key', help=('The access key for your ISBNDB.com account. ' 'Only needed if you want to search isbndb.com')) parser.add_option('-v', '--verbose', default=0, action='count', @@ -135,19 +137,19 @@ def option_parser(): def main(args=sys.argv): parser = option_parser() opts, args = parser.parse_args(args) - results, exceptions = search(opts.title, opts.author, opts.publisher, + results, exceptions = search(opts.title, opts.author, opts.publisher, opts.isbn, opts.isbndb_key, opts.verbose) for result in results: print unicode(result).encode(preferred_encoding) print - + for name, exception, tb in exceptions: if exception is not None: print 'WARNING: Fetching from', name, 'failed with error:' print exception print tb - + return 0 - + if __name__ == '__main__': - sys.exit(main()) \ No newline at end of file + sys.exit(main()) diff --git a/src/calibre/gui2/dialogs/jobs.py b/src/calibre/gui2/dialogs/jobs.py index 5b97934a84..c6907c6b60 100644 --- a/src/calibre/gui2/dialogs/jobs.py +++ b/src/calibre/gui2/dialogs/jobs.py @@ -10,10 +10,10 @@ from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog from calibre import __appname__ class ProgressBarDelegate(QAbstractItemDelegate): - + def sizeHint(self, option, index): return QSize(120, 30) - + def paint(self, painter, option, index): opts = QStyleOptionProgressBarV2() opts.rect = option.rect @@ -44,20 +44,23 @@ class JobsDialog(QDialog, Ui_JobsDialog): self.jobs_view.model().kill_job) self.pb_delegate = ProgressBarDelegate(self) self.jobs_view.setItemDelegateForColumn(2, self.pb_delegate) - + self.running_time_timer = QTimer(self) self.connect(self.running_time_timer, SIGNAL('timeout()'), self.update_running_time) self.running_time_timer.start(1000) - + def update_running_time(self, *args): - self.model.running_time_updated() - + try: + self.model.running_time_updated() + except: # Raises random exceptions on OS X + pass + def kill_job(self): for index in self.jobs_view.selectedIndexes(): row = index.row() self.model.kill_job(row, self) return - + def closeEvent(self, e): self.jobs_view.write_settings() e.accept() diff --git a/src/calibre/gui2/jobs2.py b/src/calibre/gui2/jobs2.py index 10b3853907..fc6ddb642e 100644 --- a/src/calibre/gui2/jobs2.py +++ b/src/calibre/gui2/jobs2.py @@ -18,27 +18,27 @@ from calibre.gui2.dialogs.job_view_ui import Ui_Dialog NONE = QVariant() class JobManager(QAbstractTableModel): - + def __init__(self): QAbstractTableModel.__init__(self) self.wait_icon = QVariant(QIcon(':/images/jobs.svg')) self.running_icon = QVariant(QIcon(':/images/exec.svg')) self.error_icon = QVariant(QIcon(':/images/dialog_error.svg')) self.done_icon = QVariant(QIcon(':/images/ok.svg')) - + self.jobs = [] self.server = Server() self.add_job = Dispatcher(self._add_job) self.status_update = Dispatcher(self._status_update) self.start_work = Dispatcher(self._start_work) self.job_done = Dispatcher(self._job_done) - + def columnCount(self, parent=QModelIndex()): return 4 - + def rowCount(self, parent=QModelIndex()): return len(self.jobs) - + def headerData(self, section, orientation, role): if role != Qt.DisplayRole: return NONE @@ -50,14 +50,14 @@ class JobManager(QAbstractTableModel): return QVariant(text) else: return QVariant(section+1) - + def data(self, index, role): try: if role not in (Qt.DisplayRole, Qt.DecorationRole): return NONE row, col = index.row(), index.column() job = self.jobs[row] - + if role == Qt.DisplayRole: if col == 0: desc = job.description @@ -102,31 +102,31 @@ class JobManager(QAbstractTableModel): import traceback traceback.print_exc() return NONE - + def _add_job(self, job): self.emit(SIGNAL('layoutAboutToBeChanged()')) self.jobs.append(job) self.jobs.sort() self.emit(SIGNAL('job_added(int)'), self.rowCount()) self.emit(SIGNAL('layoutChanged()')) - + def done_jobs(self): return [j for j in self.jobs if j.status() in ['DONE', 'ERROR']] - + def row_to_job(self, row): return self.jobs[row] - + def _start_work(self, job): self.emit(SIGNAL('layoutAboutToBeChanged()')) self.jobs.sort() self.emit(SIGNAL('layoutChanged()')) - + def _job_done(self, job): self.emit(SIGNAL('layoutAboutToBeChanged()')) self.jobs.sort() self.emit(SIGNAL('job_done(int)'), len(self.jobs) - len(self.done_jobs())) self.emit(SIGNAL('layoutChanged()')) - + def _status_update(self, job): try: row = self.jobs.index(job) @@ -134,38 +134,38 @@ class JobManager(QAbstractTableModel): return self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'), self.index(row, 0), self.index(row, 3)) - - def running_time_updated(self): + + def running_time_updated(self, *args): for job in self.jobs: if not job.is_running: continue row = self.jobs.index(job) self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'), - self.index(row, 3), self.index(row, 3)) - + self.index(row, 3), self.index(row, 3)) + def has_device_jobs(self): for job in self.jobs: if job.is_running and isinstance(job, DeviceJob): return True return False - + def has_jobs(self): for job in self.jobs: if job.is_running: return True return False - + def run_job(self, done, func, args=[], kwargs={}, description=None): job = ParallelJob(func, done, self, args=args, kwargs=kwargs, description=description) self.server.add_job(job) return job - - + + def output(self, job): self.emit(SIGNAL('output_received()')) - + def kill_job(self, row, view): job = self.jobs[row] if isinstance(job, DeviceJob): @@ -183,20 +183,20 @@ class JobManager(QAbstractTableModel): self.server.kill(job) - + def terminate_all_jobs(self): pass - + class DetailView(QDialog, Ui_Dialog): - + def __init__(self, parent, job): QDialog.__init__(self, parent) self.setupUi(self) self.setWindowTitle(job.description) self.job = job self.update() - - + + def update(self): self.log.setPlainText(self.job.console_text()) vbar = self.log.verticalScrollBar()