diff --git a/resources/images/devices/nook.jpg b/resources/images/devices/nook.jpg new file mode 100644 index 0000000000..1ca38d8119 Binary files /dev/null and b/resources/images/devices/nook.jpg differ diff --git a/resources/recipes/strategy-business.recipe b/resources/recipes/strategy-business.recipe new file mode 100644 index 0000000000..1ea85d6f21 --- /dev/null +++ b/resources/recipes/strategy-business.recipe @@ -0,0 +1,64 @@ +from calibre.web.feeds.news import BasicNewsRecipe + +class StrategyBusinessRecipe(BasicNewsRecipe): + __license__ = 'GPL v3' + __author__ = 'kwetal' + language = 'en' + version = 1 + + title = u'Strategy+Business' + publisher = u' Booz & Company' + category = u'Business' + description = u'Business magazine for senior business executives and the people who influence them.' + + oldest_article = 13 * 7 # 3 months + max_articles_per_feed = 100 + use_embedded_content = False + remove_empty_feeds = True + + no_stylesheets = True + remove_javascript = True + + extra_css = ''' + body{font-family:verdana,arial,helvetica,geneva,sans-serif ;} + a {text-decoration: none; color: blue;} + h1 {margin: 0em; padding: 0em;} + h2 {font-size: medium; font-weight: bold;} + #sb-date {font-size: xx-small; color: #696969} + #category {font-style: italic; font-size: small; color: black; margin: 0em; padding: 0em;} + #byline {font-size: small; color: #666666} + div.profiles {font-size: small; font-style: italic; color: #696969} + div.profiles h2 {font-size: medium; font-style: normal; font-weight: bold; color: black} + ''' + + feeds = [] + feeds.append((u'Finance', u'http://feeds.feedburner.com/StrategyBusiness-Finance?format=xml')) + feeds.append((u'Global Perspective', u'http://feeds.feedburner.com/StrategyBusiness-GlobalPerspective?format=xml')) + feeds.append((u'Innovation', u'http://feeds.feedburner.com/StrategyBusiness-Innovation?format=xml')) + feeds.append((u'Marketing And Sales', u'http://feeds.feedburner.com/StrategyBusiness-MarketingAndSales?format=xml')) + feeds.append((u'Operations And Manufacturing', u'http://feeds.feedburner.com/StrategyBusiness-OperationsAndManufacturing?format=xml')) + feeds.append((u'Organizations And People', u'http://feeds.feedburner.com/StrategyBusiness-OrganizationsAndPeople?format=xml')) + feeds.append((u'Strategy And Leadership', u'http://feeds.feedburner.com/StrategyBusiness-StrategyAndLeadership?format=xml')) + feeds.append((u'Sustainability', u'http://feeds.feedburner.com/StrategyBusiness-Sustainability?format=xml')) + feeds.append((u'Auto, Airlines And Transport', u'http://feeds.feedburner.com/StrategyBusiness-AutoAirlinesAndTransport?format=xml')) + feeds.append((u'Consumer Products', u'http://feeds.feedburner.com/StrategyBusiness-ConsumerProducts?format=xml')) + feeds.append((u'Energy', u'http://feeds.feedburner.com/StrategyBusiness-Energy?format=xml')) + feeds.append((u'Health Care', u'http://feeds.feedburner.com/StrategyBusiness-HealthCare?format=xml')) + feeds.append((u'Technology', u'http://feeds.feedburner.com/StrategyBusiness-Technology?format=xml')) + feeds.append((u'Thought Leaders', u'http://feeds.feedburner.com/StrategyBusiness-ThoughtLeaders?format=xml')) + feeds.append((u'Business Literature', u'http://feeds.feedburner.com/StrategyBusiness-BusinessLiterature?format=xml')) + feeds.append((u'Recent Research', u'http://feeds.feedburner.com/StrategyBusiness-RecentResearch?format=xml')) + + + keep_only_tags = [] + keep_only_tags.append(dict(name = 'div', attrs = {'id': 'sb-column2'})) + + remove_tags = [] + remove_tags.append(dict(name = 'img', attrs = {'class': 'content1'})) + remove_tags.append(dict(name = 'img', attrs = {'src': '/media/image/end_of_story.gif'})) + remove_tags.append(dict(name = 'div', attrs = {'class': 'sb-adarea468'})) + remove_tags.append(dict(name = 'div', attrs = {'id': 'sb-paging'})) + remove_tags.append(dict(name = 'div', attrs = {'id': 'textsize'})) + + def print_version(self, url): + return url + '?pg=all' diff --git a/resources/recipes/watchingamerica.recipe b/resources/recipes/watchingamerica.recipe new file mode 100644 index 0000000000..9048e2550c --- /dev/null +++ b/resources/recipes/watchingamerica.recipe @@ -0,0 +1,96 @@ +from calibre.web.feeds.news import BasicNewsRecipe +from calibre.ebooks.BeautifulSoup import BeautifulSoup + +class WatchingAmericaRecipe(BasicNewsRecipe): + __license__ = 'GPL v3' + __author__ = 'kwetal' + language = 'en' + version = 1 + + title = u'Watching America' + publisher = u'watchingamerica.com' + category = u'News' + description = u'Global opinion about the United States' + + oldest_article = 7 + max_articles_per_feed = 100 + use_embedded_content = False + + no_stylesheets = True + remove_javascript = True + remove_attributes = ['style'] + + extra_css = ''' + body{font-family:verdana,arial,helvetica,geneva,sans-serif ;} + .main_content em {font-size: x-small; font-style: italic; color: #696969;} + .main_content span strong {font-size: x-large; font-weight: bold;} + .insideitro {font-size: xx-small; font-style: italic; color: #666666;} + span {padding: 0em; margin 0em;} + ''' + + INDEX = u'http://watchingamerica.com/News/' + + def parse_index(self): + answer = [] + + soup = self.index_to_soup(self.INDEX) + + articles = [] + feature = soup.find('div', attrs = {'id': 'headzone'}) + if feature: + link = feature.find('a', attrs = {'class': 'feature'}) + url = link.get('href', None) + title = self.tag_to_string(link) + description = self.tag_to_string(feature.find('h1', attrs = {'class': 'pull'})) + article = {'title': title, 'date': u'', 'url': url, 'description': description} + articles.append(article) + answer.append(('Feature', articles)) + + feed_titles = ['Translations from the West', 'Translations from the East'] + for i in range(1, 3): + articles = [] + div = soup.find('div', attrs = {'class': 'newscol' + str(i)}) + if div: + for link in div.findAll('a', attrs = {'class': 'headline'}): + url = link.get('href', None) + title = self.tag_to_string(link) + + description = None + h3 = link.findNextSibling('h3') + if h3: + description = self.tag_to_string(h3) + + article = {'title': title, 'date': u'', 'url': url, 'description': description} + articles.append(article) + answer.append((feed_titles[i - 1], articles)) + + return answer + + def preprocess_html(self, soup): + freshSoup = self.get_fresh_soup(soup) + article = soup.find('p', attrs = {'class': 'MsoNormal'}).parent + if article: + article.name = 'div' + del article['width'] + article['class'] = 'main_content' + org = article.find('a', attrs = {'href': '?SHOW_ORIGINAL_TEXT'}) + if org: + org.parent.extract() + + intro = article.find('span', attrs = {'class': 'insideitro'}) + if intro: + for el in intro.findAll(['strong', 'em', 'br']): + if el.name == 'br': + el.extract() + else: + el.name = 'div' + + freshSoup.body.append(article) + + return freshSoup + + def get_fresh_soup(self, oldSoup): + freshSoup = BeautifulSoup('') + if oldSoup.head.title: + freshSoup.head.title.append(self.tag_to_string(oldSoup.head.title)) + return freshSoup diff --git a/setup/installer/osx/app/launcher.c b/setup/installer/osx/app/launcher.c index 47d1c723c2..c36909efde 100644 --- a/setup/installer/osx/app/launcher.c +++ b/setup/installer/osx/app/launcher.c @@ -1,138 +1,17 @@ +#include "util.h" #include -#include -#include -#include -#include -static const char *ERR_UNKNOWNPYTHONEXCEPTION = "An uncaught exception was raised during execution of the main script, but its class or name could not be determined"; - -static int -report_error(const char *msg) { - fprintf(stderr, msg); - fprintf(stderr, "\n"); - fflush(stderr); - return -1; -} - -// These variable must be filled in before compiling +// These variables must be filled in before compiling static const char *ENV_VARS[] = { /*ENV_VARS*/ NULL }; static const char *ENV_VAR_VALS[] = { /*ENV_VAR_VALS*/ NULL}; static char PROGRAM[] = "**PROGRAM**"; static const char MODULE[] = "**MODULE**"; +static const char FUNCTION[] = "**FUNCTION**"; +static const char PYVER[] = "**PYVER**"; -#define EXE "@executable_path/.." - -static void -set_env_vars(const char* exe_path, const char* rpath) { - int i = 0; - char buf[3*PATH_MAX]; - const char *env_var, *val; - - while(1) { - env_var = ENV_VARS[i]; - if (env_var == NULL) break; - val = ENV_VAR_VALS[i++]; - if (strstr(val, EXE) == val && strlen(val) >= strlen(EXE)+1) { - strncpy(buf, exe_path, 3*PATH_MAX-150); - strncpy(buf+strlen(exe_path), val+strlen(EXE), 150); - setenv(env_var, buf, 1); - } else - setenv(env_var, val, 1); - } - setenv("CALIBRE_LAUNCH_MODULE", MODULE, 1); - setenv("RESOURCEPATH", rpath, 1); - return; -} int -main(int argc, char * const *argv, char * const *envp) { - char *pathPtr = NULL; - char buf[3*PATH_MAX]; - int ret, i; - - - uint32_t buf_size = PATH_MAX+1; - char *ebuf = calloc(buf_size, sizeof(char)); - ret = _NSGetExecutablePath(ebuf, &buf_size); - if (ret == -1) { - free(ebuf); - ebuf = calloc(buf_size, sizeof(char)); - if (_NSGetExecutablePath(ebuf, &buf_size) != 0) - return report_error("Failed to find real path of executable."); - } - pathPtr = realpath(ebuf, buf); - if (pathPtr == NULL) { - return report_error(strerror(errno)); - } - char *t; - for (i = 0; i < 3; i++) { - t = rindex(pathPtr, '/'); - if (t == NULL) return report_error("Failed to determine bundle path."); - *t = '\0'; - } - - - - char rpath[PATH_MAX+1]; - strncpy(rpath, pathPtr, strlen(pathPtr)); - strncat(rpath, "/Contents/Resources", 50); - char exe_path[PATH_MAX+1]; - strncpy(exe_path, pathPtr, strlen(pathPtr)); - strncat(exe_path, "/Contents", 50); - - set_env_vars(exe_path, rpath); - - char main_script[PATH_MAX+1]; - strncpy(main_script, rpath, strlen(rpath)); - strncat(main_script, "/launcher.py", 20); - - Py_SetProgramName(PROGRAM); - - Py_Initialize(); - - char **argv_new = calloc(argc+1, sizeof(char *)); - argv_new[argc] = NULL; - argv_new[0] = main_script; - memcpy(&argv_new[1], &argv[1], (argc - 1) * sizeof(char *)); - PySys_SetArgv(argc, argv_new); - - FILE *main_script_file = fopen(main_script, "r"); - int rval = PyRun_SimpleFileEx(main_script_file, main_script, 1); - - while (rval != 0) { - PyObject *exc, *exceptionClassName, *v, *exceptionName; - exc = PySys_GetObject("last_type"); - - if ( !exc ) { - rval = report_error(ERR_UNKNOWNPYTHONEXCEPTION); - break; - } - - exceptionClassName = PyObject_GetAttrString(exc, "__name__"); - if (!exceptionClassName) { - rval = report_error(ERR_UNKNOWNPYTHONEXCEPTION); - break; - } - - v = PySys_GetObject("last_value"); - exceptionName = (v ? PyObject_Str(v) : NULL); - - char *class = PyString_AsString(exceptionClassName); - char *exception = ""; - Py_DecRef(exceptionClassName); - if (exceptionName) { - exception = PyString_AsString(exceptionName); - Py_DecRef(exceptionName); - } - char msg[2000]; - strncpy(msg, "An unexpected error occurred: ", 100); - strncpy(msg, class, 500); - strncpy(msg, " : ", 3); - strncpy(msg, exception, 500); - rval = report_error(msg); - break; - - } - Py_Finalize(); - return rval; +main(int argc, const char **argv, const char **envp) { + return run(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, argc, argv, envp); } + diff --git a/setup/installer/osx/app/launcher.py b/setup/installer/osx/app/launcher.py deleted file mode 100644 index 14d304e7ee..0000000000 --- a/setup/installer/osx/app/launcher.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2009, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -def _disable_linecache(): - import linecache - def fake_getline(*args, **kwargs): - return '' - linecache.orig_getline = linecache.getline - linecache.getline = fake_getline -_disable_linecache() - -def _recipes_pil_prescript(plugins): - from PIL import Image - import sys - def init(): - if Image._initialized >= 2: - return - for plugin in plugins: - try: - __import__(plugin, globals(), locals(), []) - except ImportError: - if Image.DEBUG: - print 'Image: failed to import' - print plugin, ':', sys.exc_info()[1] - if Image.OPEN or Image.SAVE: - Image._initialized = 2 - Image.init = init - - -_recipes_pil_prescript(['Hdf5StubImagePlugin', 'FitsStubImagePlugin', 'SunImagePlugin', 'GbrImagePlugin', 'PngImagePlugin', 'MicImagePlugin', 'FpxImagePlugin', 'PcxImagePlugin', 'ImImagePlugin', 'SpiderImagePlugin', 'PsdImagePlugin', 'BufrStubImagePlugin', 'SgiImagePlugin', 'McIdasImagePlugin', 'XpmImagePlugin', 'BmpImagePlugin', 'TgaImagePlugin', 'PalmImagePlugin', 'XVThumbImagePlugin', 'GribStubImagePlugin', 'ArgImagePlugin', 'PdfImagePlugin', 'ImtImagePlugin', 'GifImagePlugin', 'CurImagePlugin', 'WmfImagePlugin', 'MpegImagePlugin', 'IcoImagePlugin', 'TiffImagePlugin', 'PpmImagePlugin', 'MspImagePlugin', 'EpsImagePlugin', 'JpegImagePlugin', 'PixarImagePlugin', 'PcdImagePlugin', 'IptcImagePlugin', 'XbmImagePlugin', 'DcxImagePlugin', 'IcnsImagePlugin', 'FliImagePlugin']) - -def _run(): - global __file__ - import os, sys - base = os.environ['RESOURCEPATH'] - - sys.frozen = 'macosx_app' - sys.frameworks_dir = os.path.join(os.path.dirname(base), 'Frameworks') - sys.new_app_bundle = True - sys.site_packages = os.path.join(base, 'Python', 'site-packages') - sys.binaries_path = os.path.join(os.path.dirname(base), 'MacOS') - sys.console_binaries_path = os.path.join(os.path.dirname(base), - 'console.app', 'Contents', 'MacOS') - - exe = os.environ.get('CALIBRE_LAUNCH_MODULE', 'calibre.gui2.main') - exe = os.path.join(base, 'Python', 'site-packages', *exe.split('.')) - exe += '.py' - sys.argv[0] = __file__ = exe - for arg in list(sys.argv[1:]): - if arg.startswith('-psn'): - sys.argv.remove(arg) - execfile(exe, globals(), globals()) - -_run() diff --git a/setup/installer/osx/app/main.py b/setup/installer/osx/app/main.py index e1819c9bfc..bde50376f7 100644 --- a/setup/installer/osx/app/main.py +++ b/setup/installer/osx/app/main.py @@ -10,33 +10,58 @@ import sys, os, shutil, plistlib, subprocess, glob, zipfile, tempfile, \ py_compile, stat, operator abspath, join, basename = os.path.abspath, os.path.join, os.path.basename -#TODO: WMF support in ImageMagick - -l = {} -exec open('setup.py').read() in l -VERSION = l['VERSION'] -APPNAME = l['APPNAME'] -scripts = l['scripts'] -basenames = l['basenames'] -main_functions = l['main_functions'] -main_modules = l['main_modules'] +from setup import __version__ as VERSION, __appname__ as APPNAME, basenames, \ + modules as main_modules, Command, SRC, functions as main_functions LICENSE = open('LICENSE', 'rb').read() ENV = dict( - PYTHONPATH='@executable_path/../Resources/Python/site-packages', - PYTHONHOME='@executable_path/../Resources/Python', FC_CONFIG_DIR='@executable_path/../Resources/fonts', MAGICK_HOME='@executable_path/../Frameworks/ImageMagick', QT_PLUGIN_PATH='@executable_path/../MacOS', - PYTHONDONTWRITEBYTECODE='1', - PYTHONIOENCODING='utf-8:replace', - PYTHONOPTIMIZE='2', + PYTHONIOENCODING='UTF-8', ) SW = os.environ.get('SW', '/sw') -def compile_launchers(contents_dir, xprograms): +info = warn = None + +class OSX32_Freeze(Command): + + description = 'Freeze OSX calibre installation' + + def add_options(self, parser): + parser.add_option('--test-launchers', default=False, + action='store_true', + help='Only build launchers') + + + def run(self, opts): + global info, warn + info, warn = self.info, self.warn + main(opts.test_launchers) + +def compile_launcher_lib(contents_dir, gcc, base): + info('\tCompiling calibre_launcher.dylib') + fd = join(contents_dir, 'Frameworks') + dest = join(fd, 'calibre-launcher.dylib') + src = join(base, 'util.c') + cmd = [gcc] + '-Wall -arch i386 -arch ppc -dynamiclib -std=gnu99'.split() + [src] + \ + ['-I'+base] + \ + ['-I%s/python/Python.framework/Headers'%SW] + \ + '-current_version 1.0 -compatibility_version 1.0'.split() + \ + '-fvisibility=hidden -o'.split() + [dest, '-F%s/python'%SW] + \ + ['-install_name', + '@executable_path/../Frameworks/'+os.path.basename(dest)] + \ + ['-framework', 'Python', '-framework', 'CoreFoundation', '-headerpad_max_install_names'] + info('\t'+' '.join(cmd)) + sys.stdout.flush() + subprocess.check_call(cmd) + return dest + + +def compile_launchers(contents_dir, xprograms, pyver): gcc = os.environ.get('CC', 'gcc') base = os.path.dirname(__file__) + lib = compile_launcher_lib(contents_dir, gcc, base) src = open(join(base, 'launcher.c'), 'rb').read() env, env_vals = [], [] for key, val in ENV.items(): @@ -46,22 +71,23 @@ def compile_launchers(contents_dir, xprograms): env_vals = ', '.join(env_vals)+', ' src = src.replace('/*ENV_VARS*/', env) src = src.replace('/*ENV_VAR_VALS*/', env_vals) - programs = [] - for program, module in xprograms.items(): - print '\tCompiling', program + programs = [lib] + for program, x in xprograms.items(): + module, func = x + info('\tCompiling', program) out = join(contents_dir, 'MacOS', program) programs.append(out) psrc = src.replace('**PROGRAM**', program) psrc = psrc.replace('**MODULE**', module) + psrc = psrc.replace('**FUNCTION**', func) + psrc = psrc.replace('**PYVER**', pyver) fsrc = '/tmp/%s.c'%program with open(fsrc, 'wb') as f: f.write(psrc) - cmd = [gcc, '-Wall', '-arch', 'x86_64', - '-I%s/python/Python.framework/Headers'%SW, - fsrc, '-o', out, '-F%s/python'%SW, - '-framework', 'Python', '-framework', 'CoreFoundation', + cmd = [gcc, '-Wall', '-arch', 'ppc', '-arch', 'i386', + '-I'+base, fsrc, lib, '-o', out, '-headerpad_max_install_names'] - print ' '.join(cmd) + info('\t'+' '.join(cmd)) sys.stdout.flush() subprocess.check_call(cmd) return programs @@ -81,7 +107,7 @@ def flipwritable(fn, mode=None): def thin(path): try: subprocess.check_call(['lipo', path, '-verify_arch', 'ppc64']) - print '\tThinning', path + info('\tThinning', path) except: return else: @@ -92,7 +118,7 @@ def strip_files(files, argv_max=(256 * 1024)): """ Strip a list of files """ - tostrip = [(fn, flipwritable(fn)) for fn in files] + tostrip = [(fn, flipwritable(fn)) for fn in files if os.path.exists(fn)] while tostrip: cmd = list(STRIPCMD) flips = [] @@ -125,61 +151,66 @@ class Py2App(object): FID = '@executable_path/../Frameworks' - def __init__(self, build_dir): + def __init__(self, build_dir, test_launchers=False): self.build_dir = build_dir self.contents_dir = join(self.build_dir, 'Contents') self.resources_dir = join(self.contents_dir, 'Resources') self.frameworks_dir = join(self.contents_dir, 'Frameworks') self.version_info = '.'.join(map(str, sys.version_info[:2])) + self.site_packages = join(self.resources_dir, 'Python', 'site-packages') self.to_strip = [] self.warnings = [] + self.run(test_launchers) + def warn(self, *args): - self.warnings.append(args) - prefix = '' if args and args[0].startswith('WARNING:') else 'WARNING: ' - sys.stdout.write(prefix+' '.join(args)+'\n') - sys.stdout.flush() + warn(*args) + def run(self, test_launchers): + ret = 0 + if not test_launchers: + if os.path.exists(self.build_dir): + shutil.rmtree(self.build_dir) + os.makedirs(self.build_dir) + self.create_skeleton() + self.create_plist() - def run(self): - self.create_skeleton() - self.create_plist() + self.add_python_framework() + self.add_qt_frameworks() + self.add_calibre_plugins() + self.add_podofo() + self.add_poppler() + self.add_libjpeg() + self.add_libpng() + self.add_fontconfig() + self.add_imagemagick() + self.add_misc_libraries() - self.add_python_framework() - self.add_qt_frameworks() - self.add_calibre_plugins() - self.add_podofo() - self.add_poppler() - self.add_libjpeg() - self.add_libpng() - self.add_fontconfig() - self.add_imagemagick() - self.add_misc_libraries() + self.add_site_packages() + self.add_stdlib() + self.add_resources() + self.compile_py_modules() - self.add_site_packages() - self.add_stdlib() - self.compile_py_modules() + self.create_console_app() - self.create_console_app() - - self.copy_launcher_and_site() + self.copy_site() self.create_exe() - self.thin_to_x86_64() - self.strip_files() + if not test_launchers: + #self.thin_to_x86_64() + self.strip_files() - ret = self.makedmg(self.build_dir, APPNAME+'-'+VERSION+'-x86_64') - sys.stdout.flush() - sys.stderr.flush() + ret = self.makedmg(self.build_dir, APPNAME+'-'+VERSION) - print '\nThere were', len(self.warnings), 'warnings' - for w in list(self.warnings): - print - self.warn(*w) return ret + @flush + def add_resources(self): + shutil.copytree('resources', os.path.join(self.resources_dir, + 'resources')) + @flush def thin_to_x86_64(self): - print '\nThinning to x86_64' + info('\nThinning to x86_64') for y in (self.frameworks_dir, join(self.resources_dir, 'Python')): for x in os.walk(y): for f in x[-1]: @@ -192,24 +223,22 @@ class Py2App(object): @flush def strip_files(self): - print '\nStripping files...' + info('\nStripping files...') strip_files(self.to_strip) @flush def create_exe(self): - print '\nCreating launchers' + info('\nCreating launchers') programs = {} - for program, module in zip(basenames['console'], - main_modules['console'])+zip(basenames['gui'], - main_modules['gui']): - programs[program] = module - programs = compile_launchers(self.contents_dir, programs) + progs = [] + for x in ('console', 'gui'): + progs += list(zip(basenames[x], main_modules[x], main_functions[x])) + for program, module, func in progs: + programs[program] = (module, func) + programs = compile_launchers(self.contents_dir, programs, + self.version_info) for out in programs: self.fix_dependencies_in_lib(out) - for module in main_modules['console'] + main_modules['gui']: - base = join(*module.split('.'))+'.py' - shutil.copy2(join('src', base), - join(self.resources_dir, 'Python', 'site-packages', base)) @flush def set_id(self, path_to_lib, new_id): @@ -233,20 +262,20 @@ class Py2App(object): def get_local_dependencies(self, path_to_lib): for x in self.get_dependencies(path_to_lib): for y in (SW+'/lib/', '/usr/local/lib/', SW+'/qt/lib/', - SW+'/python/'): + SW+'/python/', SW+'/freetype/lib/'): if x.startswith(y): yield x, x[len(y):] break @flush def change_dep(self, old_dep, new_dep, path_to_lib): - print '\tResolving dependency %s to'%old_dep, new_dep + info('\tResolving dependency %s to'%old_dep, new_dep) subprocess.check_call(['install_name_tool', '-change', old_dep, new_dep, path_to_lib]) @flush def fix_dependencies_in_lib(self, path_to_lib): - print '\nFixing dependencies in', path_to_lib + info('\nFixing dependencies in', path_to_lib) self.to_strip.append(path_to_lib) old_mode = flipwritable(path_to_lib) for dep, bname in self.get_local_dependencies(path_to_lib): @@ -259,7 +288,7 @@ class Py2App(object): @flush def add_python_framework(self): - print '\nAdding Python framework' + info('\nAdding Python framework') src = join(SW, 'python', 'Python.framework') x = join(self.frameworks_dir, 'Python.framework') curr = os.path.realpath(join(src, 'Versions', 'Current')) @@ -274,7 +303,7 @@ class Py2App(object): @flush def add_qt_frameworks(self): for f in ('QtCore', 'QtGui', 'QtXml', 'QtNetwork', 'QtSvg', 'QtWebkit', - 'phonon'): + 'QtXmlPatterns', 'phonon'): self.add_qt_framework(f) for d in glob.glob(join(SW, 'qt', 'plugins', '*')): shutil.copytree(d, join(self.contents_dir, 'MacOS', basename(d))) @@ -353,30 +382,30 @@ class Py2App(object): @flush def add_podofo(self): - print '\nAdding PoDoFo' + info('\nAdding PoDoFo') pdf = join(SW, 'lib', 'libpodofo.0.6.99.dylib') self.install_dylib(pdf) @flush def add_poppler(self): - print '\nAdding poppler' - for x in ('libpoppler.4.dylib', 'libpoppler-qt4.3.dylib'): + info('\nAdding poppler') + for x in ('libpoppler.5.dylib', 'libpoppler-qt4.3.dylib'): self.install_dylib(os.path.join(SW, 'lib', x)) self.install_dylib(os.path.join(SW, 'bin', 'pdftohtml'), False) @flush def add_libjpeg(self): - print '\nAdding libjpeg' + info('\nAdding libjpeg') self.install_dylib(os.path.join(SW, 'lib', 'libjpeg.7.dylib')) @flush def add_libpng(self): - print '\nAdding libpng' + info('\nAdding libpng') self.install_dylib(os.path.join(SW, 'lib', 'libpng12.0.dylib')) @flush def add_fontconfig(self): - print '\nAdding fontconfig' + info('\nAdding fontconfig') for x in ('fontconfig.1', 'freetype.6', 'expat.1'): src = os.path.join(SW, 'lib', 'lib'+x+'.dylib') self.install_dylib(src) @@ -400,7 +429,7 @@ class Py2App(object): @flush def add_imagemagick(self): - print '\nAdding ImageMagick' + info('\nAdding ImageMagick') for x in ('Wand', 'Core'): self.install_dylib(os.path.join(SW, 'lib', 'libMagick%s.2.dylib'%x)) idir = glob.glob(os.path.join(SW, 'lib', 'ImageMagick-*'))[-1] @@ -419,16 +448,15 @@ class Py2App(object): @flush def add_misc_libraries(self): - for x in ('usb', 'unrar', 'readline.6.0'): - print '\nAdding', x + for x in ('usb', 'unrar', 'readline.6.0', 'wmflite-0.2.7'): + info('\nAdding', x) x = 'lib%s.dylib'%x shutil.copy2(join(SW, 'lib', x), self.frameworks_dir) self.set_id(join(self.frameworks_dir, x), self.FID+'/'+x) @flush def add_site_packages(self): - print '\nAdding site-packages' - self.site_packages = join(self.resources_dir, 'Python', 'site-packages') + info('\nAdding site-packages') os.makedirs(self.site_packages) paths = reversed(map(abspath, [x for x in sys.path if x.startswith('/')])) upaths = [] @@ -455,12 +483,12 @@ class Py2App(object): finally: if tdir is not None: shutil.rmtree(tdir) + shutil.rmtree(os.path.join(self.site_packages, 'calibre', 'plugins')) self.remove_bytecode(join(self.resources_dir, 'Python', 'site-packages')) @flush def add_modules_from_dir(self, src): for x in glob.glob(join(src, '*.py'))+glob.glob(join(src, '*.so')): - dest = join(self.site_packages, basename(x)) shutil.copy2(x, self.site_packages) if x.endswith('.so'): self.fix_dependencies_in_lib(x) @@ -507,7 +535,7 @@ class Py2App(object): @flush def add_stdlib(self): - print '\nAdding python stdlib' + info('\nAdding python stdlib') src = join(SW, 'python/Python.framework/Versions/Current/lib/python') src += self.version_info dest = join(self.resources_dir, 'Python', 'lib', 'python') @@ -537,7 +565,7 @@ class Py2App(object): @flush def compile_py_modules(self): - print '\nCompiling Python modules' + info( '\nCompiling Python modules') base = join(self.resources_dir, 'Python') for x in os.walk(base): root = x[0] @@ -553,7 +581,7 @@ class Py2App(object): @flush def create_console_app(self): - print '\nCreating console.app' + info( '\nCreating console.app') cc_dir = os.path.join(self.contents_dir, 'console.app', 'Contents') os.makedirs(cc_dir) for x in os.listdir(self.contents_dir): @@ -568,9 +596,8 @@ class Py2App(object): join(cc_dir, x)) @flush - def copy_launcher_and_site(self): + def copy_site(self): base = os.path.dirname(__file__) - shutil.copy2(join(base, 'launcher.py'), self.resources_dir) shutil.copy2(join(base, 'site.py'), join(self.resources_dir, 'Python', 'lib', 'python'+self.version_info)) @@ -581,7 +608,7 @@ class Py2App(object): internet_enable=True, format='UDBZ'): ''' Copy a directory d into a dmg named volname ''' - print '\nCreating dmg' + info('\nCreating dmg') sys.stdout.flush() if not os.path.exists(destdir): os.makedirs(destdir) @@ -593,7 +620,7 @@ class Py2App(object): if internet_enable: subprocess.check_call(['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg]) size = os.stat(dmg).st_size/(1024*1024.) - print '\nInstaller size: %.2fMB\n'%size + info('\nInstaller size: %.2fMB\n'%size) return dmg def test_exe(): @@ -603,15 +630,11 @@ def test_exe(): return 0 -def main(): +def main(test=False): if 'test_exe' in sys.argv: return test_exe() - build_dir = abspath(join('build', APPNAME+'.app')) - if os.path.exists(build_dir): - shutil.rmtree(build_dir) - os.makedirs(build_dir) - py2app = Py2App(build_dir) - py2app.run() + build_dir = abspath(join(os.path.dirname(SRC), 'build', APPNAME+'.app')) + Py2App(build_dir, test_launchers=test) return 0 diff --git a/setup/installer/osx/app/site.py b/setup/installer/osx/app/site.py index 4c98a871ca..5232706727 100644 --- a/setup/installer/osx/app/site.py +++ b/setup/installer/osx/app/site.py @@ -11,11 +11,15 @@ def makepath(*paths): dir = os.path.abspath(os.path.join(*paths)) return dir, os.path.normcase(dir) -for m in sys.modules.values(): - f = getattr(m, '__file__', None) - if isinstance(f, basestring) and os.path.exists(f): - m.__file__ = os.path.abspath(m.__file__) -del m +def abs__file__(): + """Set all module __file__ attribute to an absolute path""" + for m in sys.modules.values(): + if hasattr(m, '__loader__'): + continue # don't mess with a PEP 302-supplied __file__ + try: + m.__file__ = os.path.abspath(m.__file__) + except AttributeError: + continue # This ensures that the initial path provided by the interpreter contains # only absolute pathnames, even if we're running from the build directory. @@ -104,3 +108,42 @@ sys.setdefaultencoding('utf-8') # if hasattr(sys, "setdefaultencoding"): del sys.setdefaultencoding + +def run_entry_point(): + bname, mod, func = sys.calibre_basename, sys.calibre_module, sys.calibre_function + sys.argv[0] = bname + pmod = __import__(mod, fromlist=[1], level=0) + return getattr(pmod, func)() + +def add_calibre_vars(base): + sys.frameworks_dir = os.path.join(os.path.dirname(base), 'Frameworks') + sys.resources_location = os.path.abspath(os.path.join(base, 'resources')) + sys.extensions_location = os.path.join(sys.frameworks_dir, 'plugins') + sys.binaries_path = os.path.join(os.path.dirname(base), 'MacOS') + sys.console_binaries_path = os.path.join(os.path.dirname(base), + 'console.app', 'Contents', 'MacOS') + + dv = os.environ.get('CALIBRE_DEVELOP_FROM', None) + if dv and os.path.exists(dv): + sys.path.insert(0, os.path.abspath(dv)) + + +def main(): + global __file__ + base = sys.resourcepath + + sys.frozen = 'macosx_app' + sys.new_app_bundle = True + abs__file__() + + add_calibre_vars(base) + addsitedir(sys.site_packages) + + + for arg in list(sys.argv[1:]): + if arg.startswith('-psn'): + sys.argv.remove(arg) + + return run_entry_point() + + diff --git a/setup/installer/osx/app/util.c b/setup/installer/osx/app/util.c new file mode 100644 index 0000000000..763e07a309 --- /dev/null +++ b/setup/installer/osx/app/util.c @@ -0,0 +1,220 @@ +#include "util.h" +#include +#include +#include +#include +#include + +#define EXPORT __attribute__((visibility("default"))) + +static const char *ERR_OOM = "Out of memory"; + +static int +report_error(const char *msg) { + fprintf(stderr, msg); + fprintf(stderr, "\n"); + fflush(stderr); + return -1; +} + +static int +report_code(const char *preamble, const char* msg, int code) { + fprintf(stderr, "%s: %s\n", preamble, msg); + fflush(stderr); + return code; +} + +#define EXE "@executable_path/.." + +static void +set_env_vars(const char **ENV_VARS, const char **ENV_VAR_VALS, const char* exe_path) { + int i = 0; + char buf[3*PATH_MAX]; + const char *env_var, *val; + + while(1) { + env_var = ENV_VARS[i]; + if (env_var == NULL) break; + val = ENV_VAR_VALS[i++]; + if (strstr(val, EXE) == val && strlen(val) >= strlen(EXE)+1) { + strncpy(buf, exe_path, 3*PATH_MAX-150); + strncpy(buf+strlen(exe_path), val+strlen(EXE), 150); + setenv(env_var, buf, 1); + } else + setenv(env_var, val, 1); + } + return; +} + +void initialize_interpreter(const char **ENV_VARS, const char **ENV_VAR_VALS, + char *PROGRAM, const char *MODULE, const char *FUNCTION, const char *PYVER, + const char* exe_path, const char *rpath, int argc, const char **argv) { + PyObject *pargv, *v; + int i; + Py_OptimizeFlag = 2; + Py_NoSiteFlag = 1; + Py_DontWriteBytecodeFlag = 1; + Py_IgnoreEnvironmentFlag = 1; + Py_NoUserSiteDirectory = 1; + + //Py_VerboseFlag = 1; + //Py_DebugFlag = 1; + + Py_SetProgramName(PROGRAM); + + char pyhome[1000]; + snprintf(pyhome, 1000, "%s/Python", rpath); + Py_SetPythonHome(pyhome); + + set_env_vars(ENV_VARS, ENV_VAR_VALS, exe_path); + + //printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath()); + Py_Initialize(); + + char *dummy_argv[1] = {""}; + PySys_SetArgv(1, dummy_argv); + //printf("Path after Py_Initialize(): %s\r\n\n", Py_GetPath()); + char path[3000]; + snprintf(path, 3000, "%s/lib/python%s:%s/lib/python%s/lib-dynload:%s/site-packages", pyhome, PYVER, pyhome, PYVER, pyhome); + + PySys_SetPath(path); + //printf("Path set by me: %s\r\n\n", path); + + PySys_SetObject("calibre_basename", PyBytes_FromString(PROGRAM)); + PySys_SetObject("calibre_module", PyBytes_FromString(MODULE)); + PySys_SetObject("calibre_function", PyBytes_FromString(FUNCTION)); + PySys_SetObject("resourcepath", PyBytes_FromString(rpath)); + snprintf(path, 3000, "%s/site-packages", pyhome); + PySys_SetObject("site_packages", PyBytes_FromString(pyhome)); + + + pargv = PyList_New(argc); + if (pargv == NULL) exit(report_error(ERR_OOM)); + for (i = 0; i < argc; i++) { + v = PyBytes_FromString(argv[i]); + if (v == NULL) exit(report_error(ERR_OOM)); + PyList_SetItem(pargv, i, v); + } + PySys_SetObject("argv", pargv); + +} + + +int pyobject_to_int(PyObject *res) { + int ret; PyObject *tmp; + tmp = PyNumber_Int(res); + if (tmp == NULL) ret = (PyObject_IsTrue(res)) ? 1 : 0; + else ret = (int)PyInt_AS_LONG(tmp); + + return ret; +} + +int handle_sysexit(PyObject *e) { + PyObject *code; + + code = PyObject_GetAttrString(e, "code"); + if (!code) return 0; + return pyobject_to_int(code); +} + +int calibre_show_python_error(const char *preamble, int code) { + PyObject *exc, *val, *tb, *str; + int ret, issysexit = 0; char *i; + + if (!PyErr_Occurred()) return code; + issysexit = PyErr_ExceptionMatches(PyExc_SystemExit); + + PyErr_Fetch(&exc, &val, &tb); + + if (exc != NULL) { + PyErr_NormalizeException(&exc, &val, &tb); + + if (issysexit) { + return (val) ? handle_sysexit(val) : 0; + } + if (val != NULL) { + str = PyObject_Unicode(val); + if (str == NULL) { + PyErr_Clear(); + str = PyObject_Str(val); + } + i = PyString_AsString(str); + ret = report_code(preamble, (i==NULL)?ERR_OOM:i, code); + if (tb != NULL) { + PyErr_Restore(exc, val, tb); + PyErr_Print(); + } + return ret; + } + } + return report_code(preamble, "", code); +} + +EXPORT +int +run(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM, + const char *MODULE, const char *FUNCTION, const char *PYVER, + int argc, const char **argv, const char **envp) { + char *pathPtr = NULL; + char buf[3*PATH_MAX]; + int ret = 0, i; + PyObject *site, *mainf, *res; + + + uint32_t buf_size = PATH_MAX+1; + char *ebuf = calloc(buf_size, sizeof(char)); + ret = _NSGetExecutablePath(ebuf, &buf_size); + if (ret == -1) { + free(ebuf); + ebuf = calloc(buf_size, sizeof(char)); + if (_NSGetExecutablePath(ebuf, &buf_size) != 0) + return report_error("Failed to find real path of executable."); + } + pathPtr = realpath(ebuf, buf); + if (pathPtr == NULL) { + return report_error(strerror(errno)); + } + char *t; + for (i = 0; i < 3; i++) { + t = rindex(pathPtr, '/'); + if (t == NULL) return report_error("Failed to determine bundle path."); + *t = '\0'; + } + + + + char rpath[PATH_MAX+1], exe_path[PATH_MAX+1]; + snprintf(exe_path, PATH_MAX+1, "%s/Contents", pathPtr); + snprintf(rpath, PATH_MAX+1, "%s/Resources", exe_path); + initialize_interpreter(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, + exe_path, rpath, argc, argv); + + site = PyImport_ImportModule("site"); + + if (site == NULL) + ret = calibre_show_python_error("Failed to import site module", -1); + else { + Py_XINCREF(site); + + mainf = PyObject_GetAttrString(site, "main"); + if (mainf == NULL || !PyCallable_Check(mainf)) + ret = calibre_show_python_error("site module has no main function", -1); + else { + Py_XINCREF(mainf); + res = PyObject_CallObject(mainf, NULL); + + if (res == NULL) + ret = calibre_show_python_error("Python function terminated unexpectedly", -1); + else { + } + } + } + PyErr_Clear(); + Py_Finalize(); + + //printf("11111 Returning: %d\r\n", ret); + return ret; +} + + + diff --git a/setup/installer/osx/app/util.h b/setup/installer/osx/app/util.h new file mode 100644 index 0000000000..636af4db13 --- /dev/null +++ b/setup/installer/osx/app/util.h @@ -0,0 +1,5 @@ +#pragma once + +int run(const char **ENV_VARS, const char **ENV_VAR_VALS, char *PROGRAM, + const char *MODULE, const char *FUNCTION, const char *PYVER, + int argc, const char **argv, const char **envp); diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py index ccef0f39e4..f63bbd9ade 100644 --- a/src/calibre/__init__.py +++ b/src/calibre/__init__.py @@ -11,8 +11,6 @@ from math import floor warnings.simplefilter('ignore', DeprecationWarning) -from PyQt4.QtCore import QUrl -from PyQt4.QtGui import QDesktopServices from calibre.startup import plugins, winutil, winutilerror from calibre.constants import iswindows, isosx, islinux, isfrozen, \ terminal_controller, preferred_encoding, \ @@ -140,9 +138,6 @@ def prints(*args, **kwargs): class CommandLineError(Exception): pass - - - def setup_cli_handlers(logger, level): if os.environ.get('CALIBRE_WORKER', None) is not None and logger.handlers: return @@ -347,6 +342,8 @@ def detect_ncpus(): def launch(path_or_url): + from PyQt4.QtCore import QUrl + from PyQt4.QtGui import QDesktopServices if os.path.exists(path_or_url): path_or_url = 'file:'+path_or_url QDesktopServices.openUrl(QUrl(path_or_url)) @@ -456,6 +453,60 @@ def ipython(user_ns=None): from calibre.utils.config import config_dir ipydir = os.path.join(config_dir, ('_' if iswindows else '.')+'ipython') os.environ['IPYTHONDIR'] = ipydir + if not os.path.exists(ipydir): + os.makedirs(ipydir) + rc = os.path.join(ipydir, 'ipythonrc') + if not os.path.exists(rc): + open(rc, 'wb').write(' ') + UC = ''' +import IPython.ipapi +ip = IPython.ipapi.get() + +# You probably want to uncomment this if you did %upgrade -nolegacy +import ipy_defaults + +import os, re, sys + +def main(): + # Handy tab-completers for %cd, %run, import etc. + # Try commenting this out if you have completion problems/slowness + import ipy_stock_completers + + # uncomment if you want to get ipython -p sh behaviour + # without having to use command line switches + + import ipy_profile_sh + + + # Configure your favourite editor? + # Good idea e.g. for %edit os.path.isfile + + import ipy_editors + + # Choose one of these: + + #ipy_editors.scite() + #ipy_editors.scite('c:/opt/scite/scite.exe') + #ipy_editors.komodo() + #ipy_editors.idle() + # ... or many others, try 'ipy_editors??' after import to see them + + # Or roll your own: + #ipy_editors.install_editor("c:/opt/jed +$line $file") + + ipy_editors.kate() + + o = ip.options + # An example on how to set options + #o.autocall = 1 + o.system_verbose = 0 + o.confirm_exit = 0 + +main() + ''' + uc = os.path.join(ipydir, 'ipy_user_conf.py') + if not os.path.exists(uc): + open(uc, 'wb').write(UC) from IPython.Shell import IPShellEmbed ipshell = IPShellEmbed(user_ns=user_ns) ipshell() diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 9e53a433ad..5b95f8f489 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -417,6 +417,7 @@ from calibre.devices.nokia.driver import N770, N810 from calibre.devices.eslick.driver import ESLICK from calibre.devices.nuut2.driver import NUUT2 from calibre.devices.iriver.driver import IRIVER_STORY +from calibre.devices.boox.driver import BOOX from calibre.ebooks.metadata.fetch import GoogleBooks, ISBNDB, Amazon plugins = [HTML2ZIP, PML2PMLZ, GoogleBooks, ISBNDB, Amazon] @@ -481,6 +482,7 @@ plugins += [ ITALICA, SHINEBOOK, ECLICTO, + BOOX, EB600, ] plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ diff --git a/src/calibre/devices/boox/__init__.py b/src/calibre/devices/boox/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/calibre/devices/boox/driver.py b/src/calibre/devices/boox/driver.py new file mode 100644 index 0000000000..85495c459c --- /dev/null +++ b/src/calibre/devices/boox/driver.py @@ -0,0 +1,87 @@ +__license__ = 'GPL v3' +__copyright__ = '2009, Jesus Manuel Marinho Valcarce ' +__docformat__ = 'restructuredtext en' + +''' +Device driver for BOOX +''' + +import re + +from calibre.devices.usbms.driver import USBMS + +class BOOX(USBMS): + + name = 'BOOX driver' + gui_name = 'BOOX' + description = _('Communicate with the BOOX eBook reader.') + author = 'Jesus Manuel Marinho Valcarce' + supported_platforms = ['windows', 'osx', 'linux'] + + # Ordered list of supported formats + FORMATS = ['ebub', 'pdf', 'html', 'txt', 'rtf', 'mobi', 'prc', 'chm'] + + VENDOR_ID = [0x0525] + PRODUCT_ID = [0xa4a5] + BCD = [0x322] + + VENDOR_NAME = 'Linux 2.6.26-466-ga04670e with fsl-usb2-udc' + WINDOWS_MAIN_MEM = 'FILE-STOR_GADGET' + WINDOWS_CARD_A_MEM = 'FILE-STOR_GADGET' + + OSX_MAIN_MEM = 'Linux File-Stor Gadget Media' + OSX_CARD_A_MEM = 'Linux File-Stor Gadget Media' + + MAIN_MEMORY_VOLUME_LABEL = 'BOOX Internal Memory' + STORAGE_CARD_VOLUME_LABEL = 'BOOX Storage Card' + + EBOOK_DIR_MAIN = 'MyBooks' + EBOOK_DIR_CARD_A = 'MyBooks' + SUPPORTS_SUB_DIRS = True + + def windows_sort_drives(self, drives): + main = drives.get('main', None) + card = drives.get('carda', None) + if card and main and card > main: + drives['main'] = card + drives['carda'] = main + + if card and not main: + drives['main'] = card + drives['carda'] = None + + return drives + + def osx_sort_names(self, names): + main = names.get('main', None) + card = names.get('carda', None) + + try: + main_num = int(re.findall('\d+', main)[0]) if main else None + except: + main_num = None + try: + card_num = int(re.findall('\d+', card)[0]) if card else None + except: + card_num = None + + if card_num is not None and main_num is not None and card_num > main_num: + names['main'] = card + names['carda'] = main + + if card and not main: + names['main'] = card + names['carda'] = None + + return names + + def linux_swap_drives(self, drives): + if len(drives) < 2: return drives + drives = list(drives) + t = drives[0] + drives[0] = drives[1] + drives[1] = t + return tuple(drives) + + + diff --git a/src/calibre/devices/nook/driver.py b/src/calibre/devices/nook/driver.py index cc3f26d730..332c4d86eb 100644 --- a/src/calibre/devices/nook/driver.py +++ b/src/calibre/devices/nook/driver.py @@ -23,6 +23,7 @@ class NOOK(USBMS): gui_name = _('The Nook') description = _('Communicate with the Nook eBook reader.') author = 'John Schember' + icon = I('devices/nook.jpg') supported_platforms = ['windows', 'linux', 'osx'] # Ordered list of supported formats diff --git a/src/calibre/ebooks/comic/input.py b/src/calibre/ebooks/comic/input.py index f0acfe3a06..85590a7bae 100755 --- a/src/calibre/ebooks/comic/input.py +++ b/src/calibre/ebooks/comic/input.py @@ -8,6 +8,7 @@ Based on ideas from comiclrf created by FangornUK. ''' import os, shutil, traceback, textwrap, time +from ctypes import byref from Queue import Empty from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation @@ -75,7 +76,10 @@ class PageProcessor(list): if img < 0: raise RuntimeError('Cannot create wand.') if not pw.MagickReadImage(img, self.path_to_page): - raise IOError('Failed to read image from: %'%self.path_to_page) + severity = pw.ExceptionType(0) + msg = pw.MagickGetException(img, byref(severity)) + raise IOError('Failed to read image from: %s: %s' + %(self.path_to_page, msg)) width = pw.MagickGetImageWidth(img) height = pw.MagickGetImageHeight(img) if self.num == 0: # First image so create a thumbnail from it @@ -363,14 +367,14 @@ class ComicInput(InputFormatPlugin): else: new_pages, failures = process_pages(new_pages, self.opts, self.report_progress, tdir2) - if not new_pages: - raise ValueError('Could not find any valid pages in comic: %s' - % comic) if failures: self.log.warning('Could not process the following pages ' '(run with --verbose to see why):') for f in failures: self.log.warning('\t', f) + if not new_pages: + raise ValueError('Could not find any valid pages in comic: %s' + % comic) thumbnail = os.path.join(tdir2, 'thumbnail.'+self.opts.output_format.lower()) if not os.access(thumbnail, os.R_OK): diff --git a/src/calibre/gui2/dialogs/config/config.ui b/src/calibre/gui2/dialogs/config/config.ui index 77c1d9eccd..f593df5e14 100644 --- a/src/calibre/gui2/dialogs/config/config.ui +++ b/src/calibre/gui2/dialogs/config/config.ui @@ -7,7 +7,7 @@ 0 0 - 800 + 838 730 @@ -89,7 +89,7 @@ 0 0 - 524 + 562 683 diff --git a/src/calibre/gui2/filename_pattern.ui b/src/calibre/gui2/filename_pattern.ui index d0a4cf74b0..d120ca80b2 100644 --- a/src/calibre/gui2/filename_pattern.ui +++ b/src/calibre/gui2/filename_pattern.ui @@ -7,7 +7,7 @@ 0 0 335 - 540 + 570 @@ -84,104 +84,123 @@ p, li { white-space: pre-wrap; } - - - - Title: - - - - - - - Regular expression (?P&lt;title&gt;) - - - No match - - - true - - - - - - - Authors: - - - - - - - Regular expression (?P<author>) - - - No match - - - true - - - - - - - Series: - - - - - - - Regular expression (?P<series>) - - - No match - - - true - - - - - - - Series index: - - - - - - - Regular expression (?P<series_index>) - - - No match - - - true - - - - - - - ISBN: - - - - - - - Regular expression (?P<isbn>) - - - No match - - + + + true + + + + 0 + 0 + 301 + 234 + + + + + + + Title: + + + + + + + Regular expression (?P&lt;title&gt;) + + + No match + + + true + + + + + + + Authors: + + + + + + + Regular expression (?P<author>) + + + No match + + + true + + + + + + + Series: + + + + + + + Regular expression (?P<series>) + + + No match + + + true + + + + + + + Series index: + + + + + + + Regular expression (?P<series_index>) + + + No match + + + true + + + + + + + ISBN: + + + + + + + Regular expression (?P<isbn>) + + + No match + + + true + + + + + diff --git a/src/calibre/ptempfile.py b/src/calibre/ptempfile.py index fe69949f99..f4bcfa8675 100644 --- a/src/calibre/ptempfile.py +++ b/src/calibre/ptempfile.py @@ -46,7 +46,10 @@ class PersistentTemporaryFile(object): self.close() def __del__(self): - self.close() + try: + self.close() + except: + pass def PersistentTemporaryDirectory(suffix='', prefix='', dir=None): diff --git a/src/calibre/utils/PythonMagickWand.py b/src/calibre/utils/PythonMagickWand.py index 16ca8d2935..9920334b0a 100644 --- a/src/calibre/utils/PythonMagickWand.py +++ b/src/calibre/utils/PythonMagickWand.py @@ -828,7 +828,7 @@ else: IsMagickWand = _magick.IsMagickWand # MagickGetException try: - _magick.MagickGetException.restype = ctypes.POINTER(ctypes.c_char) + _magick.MagickGetException.restype = ctypes.c_char_p _magick.MagickGetException.argtypes = (MagickWand,ctypes.POINTER(ExceptionType)) except AttributeError,e: pass diff --git a/src/calibre/utils/osx_symlinks.py b/src/calibre/utils/osx_symlinks.py index 2cfdd72fa3..63863cb810 100644 --- a/src/calibre/utils/osx_symlinks.py +++ b/src/calibre/utils/osx_symlinks.py @@ -7,6 +7,7 @@ __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' import sys, os, cPickle +from calibre.constants import isnewosx AUTHTOOL="""#!/usr/bin/python import os @@ -27,7 +28,7 @@ for s, l in zip(scripts, links): DEST_PATH = '/usr/bin' def create_symlinks(): - return create_symlinks_new() if getattr(sys, 'new_app_bundle', False) else create_symlinks_old() + return create_symlinks_new() if isnewosx else create_symlinks_old() def get_scripts(): return cPickle.load(open(P('scripts.pickle'), 'rb'))