Sync to trunk.

This commit is contained in:
John Schember 2009-12-21 18:14:49 -05:00
commit fd81ca32a9
20 changed files with 844 additions and 404 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -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'

View File

@ -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('<html><head><title></title></head><body></body></html>')
if oldSoup.head.title:
freshSoup.head.title.append(self.tag_to_string(oldSoup.head.title))
return freshSoup

View File

@ -1,138 +1,17 @@
#include "util.h"
#include <stdlib.h> #include <stdlib.h>
#include <strings.h>
#include <CoreFoundation/CoreFoundation.h>
#include <mach-o/dyld.h>
#include <Python.h>
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"; // These variables must be filled in before compiling
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
static const char *ENV_VARS[] = { /*ENV_VARS*/ NULL }; static const char *ENV_VARS[] = { /*ENV_VARS*/ NULL };
static const char *ENV_VAR_VALS[] = { /*ENV_VAR_VALS*/ NULL}; static const char *ENV_VAR_VALS[] = { /*ENV_VAR_VALS*/ NULL};
static char PROGRAM[] = "**PROGRAM**"; static char PROGRAM[] = "**PROGRAM**";
static const char MODULE[] = "**MODULE**"; 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 int
main(int argc, char * const *argv, char * const *envp) { main(int argc, const char **argv, const char **envp) {
char *pathPtr = NULL; return run(ENV_VARS, ENV_VAR_VALS, PROGRAM, MODULE, FUNCTION, PYVER, argc, argv, envp);
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;
} }

View File

@ -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 <kovid@kovidgoyal.net>'
__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()

View File

@ -10,33 +10,58 @@ import sys, os, shutil, plistlib, subprocess, glob, zipfile, tempfile, \
py_compile, stat, operator py_compile, stat, operator
abspath, join, basename = os.path.abspath, os.path.join, os.path.basename abspath, join, basename = os.path.abspath, os.path.join, os.path.basename
#TODO: WMF support in ImageMagick from setup import __version__ as VERSION, __appname__ as APPNAME, basenames, \
modules as main_modules, Command, SRC, functions as main_functions
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']
LICENSE = open('LICENSE', 'rb').read() LICENSE = open('LICENSE', 'rb').read()
ENV = dict( ENV = dict(
PYTHONPATH='@executable_path/../Resources/Python/site-packages',
PYTHONHOME='@executable_path/../Resources/Python',
FC_CONFIG_DIR='@executable_path/../Resources/fonts', FC_CONFIG_DIR='@executable_path/../Resources/fonts',
MAGICK_HOME='@executable_path/../Frameworks/ImageMagick', MAGICK_HOME='@executable_path/../Frameworks/ImageMagick',
QT_PLUGIN_PATH='@executable_path/../MacOS', QT_PLUGIN_PATH='@executable_path/../MacOS',
PYTHONDONTWRITEBYTECODE='1', PYTHONIOENCODING='UTF-8',
PYTHONIOENCODING='utf-8:replace',
PYTHONOPTIMIZE='2',
) )
SW = os.environ.get('SW', '/sw') 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') gcc = os.environ.get('CC', 'gcc')
base = os.path.dirname(__file__) base = os.path.dirname(__file__)
lib = compile_launcher_lib(contents_dir, gcc, base)
src = open(join(base, 'launcher.c'), 'rb').read() src = open(join(base, 'launcher.c'), 'rb').read()
env, env_vals = [], [] env, env_vals = [], []
for key, val in ENV.items(): for key, val in ENV.items():
@ -46,22 +71,23 @@ def compile_launchers(contents_dir, xprograms):
env_vals = ', '.join(env_vals)+', ' env_vals = ', '.join(env_vals)+', '
src = src.replace('/*ENV_VARS*/', env) src = src.replace('/*ENV_VARS*/', env)
src = src.replace('/*ENV_VAR_VALS*/', env_vals) src = src.replace('/*ENV_VAR_VALS*/', env_vals)
programs = [] programs = [lib]
for program, module in xprograms.items(): for program, x in xprograms.items():
print '\tCompiling', program module, func = x
info('\tCompiling', program)
out = join(contents_dir, 'MacOS', program) out = join(contents_dir, 'MacOS', program)
programs.append(out) programs.append(out)
psrc = src.replace('**PROGRAM**', program) psrc = src.replace('**PROGRAM**', program)
psrc = psrc.replace('**MODULE**', module) psrc = psrc.replace('**MODULE**', module)
psrc = psrc.replace('**FUNCTION**', func)
psrc = psrc.replace('**PYVER**', pyver)
fsrc = '/tmp/%s.c'%program fsrc = '/tmp/%s.c'%program
with open(fsrc, 'wb') as f: with open(fsrc, 'wb') as f:
f.write(psrc) f.write(psrc)
cmd = [gcc, '-Wall', '-arch', 'x86_64', cmd = [gcc, '-Wall', '-arch', 'ppc', '-arch', 'i386',
'-I%s/python/Python.framework/Headers'%SW, '-I'+base, fsrc, lib, '-o', out,
fsrc, '-o', out, '-F%s/python'%SW,
'-framework', 'Python', '-framework', 'CoreFoundation',
'-headerpad_max_install_names'] '-headerpad_max_install_names']
print ' '.join(cmd) info('\t'+' '.join(cmd))
sys.stdout.flush() sys.stdout.flush()
subprocess.check_call(cmd) subprocess.check_call(cmd)
return programs return programs
@ -81,7 +107,7 @@ def flipwritable(fn, mode=None):
def thin(path): def thin(path):
try: try:
subprocess.check_call(['lipo', path, '-verify_arch', 'ppc64']) subprocess.check_call(['lipo', path, '-verify_arch', 'ppc64'])
print '\tThinning', path info('\tThinning', path)
except: except:
return return
else: else:
@ -92,7 +118,7 @@ def strip_files(files, argv_max=(256 * 1024)):
""" """
Strip a list of files 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: while tostrip:
cmd = list(STRIPCMD) cmd = list(STRIPCMD)
flips = [] flips = []
@ -125,61 +151,66 @@ class Py2App(object):
FID = '@executable_path/../Frameworks' FID = '@executable_path/../Frameworks'
def __init__(self, build_dir): def __init__(self, build_dir, test_launchers=False):
self.build_dir = build_dir self.build_dir = build_dir
self.contents_dir = join(self.build_dir, 'Contents') self.contents_dir = join(self.build_dir, 'Contents')
self.resources_dir = join(self.contents_dir, 'Resources') self.resources_dir = join(self.contents_dir, 'Resources')
self.frameworks_dir = join(self.contents_dir, 'Frameworks') self.frameworks_dir = join(self.contents_dir, 'Frameworks')
self.version_info = '.'.join(map(str, sys.version_info[:2])) self.version_info = '.'.join(map(str, sys.version_info[:2]))
self.site_packages = join(self.resources_dir, 'Python', 'site-packages')
self.to_strip = [] self.to_strip = []
self.warnings = [] self.warnings = []
self.run(test_launchers)
def warn(self, *args): def warn(self, *args):
self.warnings.append(args) warn(*args)
prefix = '' if args and args[0].startswith('WARNING:') else 'WARNING: '
sys.stdout.write(prefix+' '.join(args)+'\n')
sys.stdout.flush()
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.add_python_framework()
self.create_skeleton() self.add_qt_frameworks()
self.create_plist() 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_site_packages()
self.add_qt_frameworks() self.add_stdlib()
self.add_calibre_plugins() self.add_resources()
self.add_podofo() self.compile_py_modules()
self.add_poppler()
self.add_libjpeg()
self.add_libpng()
self.add_fontconfig()
self.add_imagemagick()
self.add_misc_libraries()
self.add_site_packages() self.create_console_app()
self.add_stdlib()
self.compile_py_modules()
self.create_console_app() self.copy_site()
self.copy_launcher_and_site()
self.create_exe() self.create_exe()
self.thin_to_x86_64() if not test_launchers:
self.strip_files() #self.thin_to_x86_64()
self.strip_files()
ret = self.makedmg(self.build_dir, APPNAME+'-'+VERSION+'-x86_64') ret = self.makedmg(self.build_dir, APPNAME+'-'+VERSION)
sys.stdout.flush()
sys.stderr.flush()
print '\nThere were', len(self.warnings), 'warnings'
for w in list(self.warnings):
print
self.warn(*w)
return ret return ret
@flush
def add_resources(self):
shutil.copytree('resources', os.path.join(self.resources_dir,
'resources'))
@flush @flush
def thin_to_x86_64(self): 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 y in (self.frameworks_dir, join(self.resources_dir, 'Python')):
for x in os.walk(y): for x in os.walk(y):
for f in x[-1]: for f in x[-1]:
@ -192,24 +223,22 @@ class Py2App(object):
@flush @flush
def strip_files(self): def strip_files(self):
print '\nStripping files...' info('\nStripping files...')
strip_files(self.to_strip) strip_files(self.to_strip)
@flush @flush
def create_exe(self): def create_exe(self):
print '\nCreating launchers' info('\nCreating launchers')
programs = {} programs = {}
for program, module in zip(basenames['console'], progs = []
main_modules['console'])+zip(basenames['gui'], for x in ('console', 'gui'):
main_modules['gui']): progs += list(zip(basenames[x], main_modules[x], main_functions[x]))
programs[program] = module for program, module, func in progs:
programs = compile_launchers(self.contents_dir, programs) programs[program] = (module, func)
programs = compile_launchers(self.contents_dir, programs,
self.version_info)
for out in programs: for out in programs:
self.fix_dependencies_in_lib(out) 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 @flush
def set_id(self, path_to_lib, new_id): def set_id(self, path_to_lib, new_id):
@ -233,20 +262,20 @@ class Py2App(object):
def get_local_dependencies(self, path_to_lib): def get_local_dependencies(self, path_to_lib):
for x in self.get_dependencies(path_to_lib): for x in self.get_dependencies(path_to_lib):
for y in (SW+'/lib/', '/usr/local/lib/', SW+'/qt/lib/', for y in (SW+'/lib/', '/usr/local/lib/', SW+'/qt/lib/',
SW+'/python/'): SW+'/python/', SW+'/freetype/lib/'):
if x.startswith(y): if x.startswith(y):
yield x, x[len(y):] yield x, x[len(y):]
break break
@flush @flush
def change_dep(self, old_dep, new_dep, path_to_lib): 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, subprocess.check_call(['install_name_tool', '-change', old_dep, new_dep,
path_to_lib]) path_to_lib])
@flush @flush
def fix_dependencies_in_lib(self, path_to_lib): 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) self.to_strip.append(path_to_lib)
old_mode = flipwritable(path_to_lib) old_mode = flipwritable(path_to_lib)
for dep, bname in self.get_local_dependencies(path_to_lib): for dep, bname in self.get_local_dependencies(path_to_lib):
@ -259,7 +288,7 @@ class Py2App(object):
@flush @flush
def add_python_framework(self): def add_python_framework(self):
print '\nAdding Python framework' info('\nAdding Python framework')
src = join(SW, 'python', 'Python.framework') src = join(SW, 'python', 'Python.framework')
x = join(self.frameworks_dir, 'Python.framework') x = join(self.frameworks_dir, 'Python.framework')
curr = os.path.realpath(join(src, 'Versions', 'Current')) curr = os.path.realpath(join(src, 'Versions', 'Current'))
@ -274,7 +303,7 @@ class Py2App(object):
@flush @flush
def add_qt_frameworks(self): def add_qt_frameworks(self):
for f in ('QtCore', 'QtGui', 'QtXml', 'QtNetwork', 'QtSvg', 'QtWebkit', for f in ('QtCore', 'QtGui', 'QtXml', 'QtNetwork', 'QtSvg', 'QtWebkit',
'phonon'): 'QtXmlPatterns', 'phonon'):
self.add_qt_framework(f) self.add_qt_framework(f)
for d in glob.glob(join(SW, 'qt', 'plugins', '*')): for d in glob.glob(join(SW, 'qt', 'plugins', '*')):
shutil.copytree(d, join(self.contents_dir, 'MacOS', basename(d))) shutil.copytree(d, join(self.contents_dir, 'MacOS', basename(d)))
@ -353,30 +382,30 @@ class Py2App(object):
@flush @flush
def add_podofo(self): def add_podofo(self):
print '\nAdding PoDoFo' info('\nAdding PoDoFo')
pdf = join(SW, 'lib', 'libpodofo.0.6.99.dylib') pdf = join(SW, 'lib', 'libpodofo.0.6.99.dylib')
self.install_dylib(pdf) self.install_dylib(pdf)
@flush @flush
def add_poppler(self): def add_poppler(self):
print '\nAdding poppler' info('\nAdding poppler')
for x in ('libpoppler.4.dylib', 'libpoppler-qt4.3.dylib'): 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, 'lib', x))
self.install_dylib(os.path.join(SW, 'bin', 'pdftohtml'), False) self.install_dylib(os.path.join(SW, 'bin', 'pdftohtml'), False)
@flush @flush
def add_libjpeg(self): def add_libjpeg(self):
print '\nAdding libjpeg' info('\nAdding libjpeg')
self.install_dylib(os.path.join(SW, 'lib', 'libjpeg.7.dylib')) self.install_dylib(os.path.join(SW, 'lib', 'libjpeg.7.dylib'))
@flush @flush
def add_libpng(self): def add_libpng(self):
print '\nAdding libpng' info('\nAdding libpng')
self.install_dylib(os.path.join(SW, 'lib', 'libpng12.0.dylib')) self.install_dylib(os.path.join(SW, 'lib', 'libpng12.0.dylib'))
@flush @flush
def add_fontconfig(self): def add_fontconfig(self):
print '\nAdding fontconfig' info('\nAdding fontconfig')
for x in ('fontconfig.1', 'freetype.6', 'expat.1'): for x in ('fontconfig.1', 'freetype.6', 'expat.1'):
src = os.path.join(SW, 'lib', 'lib'+x+'.dylib') src = os.path.join(SW, 'lib', 'lib'+x+'.dylib')
self.install_dylib(src) self.install_dylib(src)
@ -400,7 +429,7 @@ class Py2App(object):
@flush @flush
def add_imagemagick(self): def add_imagemagick(self):
print '\nAdding ImageMagick' info('\nAdding ImageMagick')
for x in ('Wand', 'Core'): for x in ('Wand', 'Core'):
self.install_dylib(os.path.join(SW, 'lib', 'libMagick%s.2.dylib'%x)) self.install_dylib(os.path.join(SW, 'lib', 'libMagick%s.2.dylib'%x))
idir = glob.glob(os.path.join(SW, 'lib', 'ImageMagick-*'))[-1] idir = glob.glob(os.path.join(SW, 'lib', 'ImageMagick-*'))[-1]
@ -419,16 +448,15 @@ class Py2App(object):
@flush @flush
def add_misc_libraries(self): def add_misc_libraries(self):
for x in ('usb', 'unrar', 'readline.6.0'): for x in ('usb', 'unrar', 'readline.6.0', 'wmflite-0.2.7'):
print '\nAdding', x info('\nAdding', x)
x = 'lib%s.dylib'%x x = 'lib%s.dylib'%x
shutil.copy2(join(SW, 'lib', x), self.frameworks_dir) shutil.copy2(join(SW, 'lib', x), self.frameworks_dir)
self.set_id(join(self.frameworks_dir, x), self.FID+'/'+x) self.set_id(join(self.frameworks_dir, x), self.FID+'/'+x)
@flush @flush
def add_site_packages(self): def add_site_packages(self):
print '\nAdding site-packages' info('\nAdding site-packages')
self.site_packages = join(self.resources_dir, 'Python', 'site-packages')
os.makedirs(self.site_packages) os.makedirs(self.site_packages)
paths = reversed(map(abspath, [x for x in sys.path if x.startswith('/')])) paths = reversed(map(abspath, [x for x in sys.path if x.startswith('/')]))
upaths = [] upaths = []
@ -455,12 +483,12 @@ class Py2App(object):
finally: finally:
if tdir is not None: if tdir is not None:
shutil.rmtree(tdir) shutil.rmtree(tdir)
shutil.rmtree(os.path.join(self.site_packages, 'calibre', 'plugins'))
self.remove_bytecode(join(self.resources_dir, 'Python', 'site-packages')) self.remove_bytecode(join(self.resources_dir, 'Python', 'site-packages'))
@flush @flush
def add_modules_from_dir(self, src): def add_modules_from_dir(self, src):
for x in glob.glob(join(src, '*.py'))+glob.glob(join(src, '*.so')): 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) shutil.copy2(x, self.site_packages)
if x.endswith('.so'): if x.endswith('.so'):
self.fix_dependencies_in_lib(x) self.fix_dependencies_in_lib(x)
@ -507,7 +535,7 @@ class Py2App(object):
@flush @flush
def add_stdlib(self): def add_stdlib(self):
print '\nAdding python stdlib' info('\nAdding python stdlib')
src = join(SW, 'python/Python.framework/Versions/Current/lib/python') src = join(SW, 'python/Python.framework/Versions/Current/lib/python')
src += self.version_info src += self.version_info
dest = join(self.resources_dir, 'Python', 'lib', 'python') dest = join(self.resources_dir, 'Python', 'lib', 'python')
@ -537,7 +565,7 @@ class Py2App(object):
@flush @flush
def compile_py_modules(self): def compile_py_modules(self):
print '\nCompiling Python modules' info( '\nCompiling Python modules')
base = join(self.resources_dir, 'Python') base = join(self.resources_dir, 'Python')
for x in os.walk(base): for x in os.walk(base):
root = x[0] root = x[0]
@ -553,7 +581,7 @@ class Py2App(object):
@flush @flush
def create_console_app(self): def create_console_app(self):
print '\nCreating console.app' info( '\nCreating console.app')
cc_dir = os.path.join(self.contents_dir, 'console.app', 'Contents') cc_dir = os.path.join(self.contents_dir, 'console.app', 'Contents')
os.makedirs(cc_dir) os.makedirs(cc_dir)
for x in os.listdir(self.contents_dir): for x in os.listdir(self.contents_dir):
@ -568,9 +596,8 @@ class Py2App(object):
join(cc_dir, x)) join(cc_dir, x))
@flush @flush
def copy_launcher_and_site(self): def copy_site(self):
base = os.path.dirname(__file__) 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', shutil.copy2(join(base, 'site.py'), join(self.resources_dir, 'Python',
'lib', 'python'+self.version_info)) 'lib', 'python'+self.version_info))
@ -581,7 +608,7 @@ class Py2App(object):
internet_enable=True, internet_enable=True,
format='UDBZ'): format='UDBZ'):
''' Copy a directory d into a dmg named volname ''' ''' Copy a directory d into a dmg named volname '''
print '\nCreating dmg' info('\nCreating dmg')
sys.stdout.flush() sys.stdout.flush()
if not os.path.exists(destdir): if not os.path.exists(destdir):
os.makedirs(destdir) os.makedirs(destdir)
@ -593,7 +620,7 @@ class Py2App(object):
if internet_enable: if internet_enable:
subprocess.check_call(['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg]) subprocess.check_call(['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg])
size = os.stat(dmg).st_size/(1024*1024.) size = os.stat(dmg).st_size/(1024*1024.)
print '\nInstaller size: %.2fMB\n'%size info('\nInstaller size: %.2fMB\n'%size)
return dmg return dmg
def test_exe(): def test_exe():
@ -603,15 +630,11 @@ def test_exe():
return 0 return 0
def main(): def main(test=False):
if 'test_exe' in sys.argv: if 'test_exe' in sys.argv:
return test_exe() return test_exe()
build_dir = abspath(join('build', APPNAME+'.app')) build_dir = abspath(join(os.path.dirname(SRC), 'build', APPNAME+'.app'))
if os.path.exists(build_dir): Py2App(build_dir, test_launchers=test)
shutil.rmtree(build_dir)
os.makedirs(build_dir)
py2app = Py2App(build_dir)
py2app.run()
return 0 return 0

View File

@ -11,11 +11,15 @@ def makepath(*paths):
dir = os.path.abspath(os.path.join(*paths)) dir = os.path.abspath(os.path.join(*paths))
return dir, os.path.normcase(dir) return dir, os.path.normcase(dir)
for m in sys.modules.values(): def abs__file__():
f = getattr(m, '__file__', None) """Set all module __file__ attribute to an absolute path"""
if isinstance(f, basestring) and os.path.exists(f): for m in sys.modules.values():
m.__file__ = os.path.abspath(m.__file__) if hasattr(m, '__loader__'):
del m 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 # This ensures that the initial path provided by the interpreter contains
# only absolute pathnames, even if we're running from the build directory. # only absolute pathnames, even if we're running from the build directory.
@ -104,3 +108,42 @@ sys.setdefaultencoding('utf-8')
# #
if hasattr(sys, "setdefaultencoding"): if hasattr(sys, "setdefaultencoding"):
del 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()

View File

@ -0,0 +1,220 @@
#include "util.h"
#include <stdlib.h>
#include <strings.h>
#include <CoreFoundation/CoreFoundation.h>
#include <mach-o/dyld.h>
#include <Python.h>
#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;
}

View File

@ -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);

View File

@ -11,8 +11,6 @@ from math import floor
warnings.simplefilter('ignore', DeprecationWarning) warnings.simplefilter('ignore', DeprecationWarning)
from PyQt4.QtCore import QUrl
from PyQt4.QtGui import QDesktopServices
from calibre.startup import plugins, winutil, winutilerror from calibre.startup import plugins, winutil, winutilerror
from calibre.constants import iswindows, isosx, islinux, isfrozen, \ from calibre.constants import iswindows, isosx, islinux, isfrozen, \
terminal_controller, preferred_encoding, \ terminal_controller, preferred_encoding, \
@ -140,9 +138,6 @@ def prints(*args, **kwargs):
class CommandLineError(Exception): class CommandLineError(Exception):
pass pass
def setup_cli_handlers(logger, level): def setup_cli_handlers(logger, level):
if os.environ.get('CALIBRE_WORKER', None) is not None and logger.handlers: if os.environ.get('CALIBRE_WORKER', None) is not None and logger.handlers:
return return
@ -347,6 +342,8 @@ def detect_ncpus():
def launch(path_or_url): def launch(path_or_url):
from PyQt4.QtCore import QUrl
from PyQt4.QtGui import QDesktopServices
if os.path.exists(path_or_url): if os.path.exists(path_or_url):
path_or_url = 'file:'+path_or_url path_or_url = 'file:'+path_or_url
QDesktopServices.openUrl(QUrl(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 from calibre.utils.config import config_dir
ipydir = os.path.join(config_dir, ('_' if iswindows else '.')+'ipython') ipydir = os.path.join(config_dir, ('_' if iswindows else '.')+'ipython')
os.environ['IPYTHONDIR'] = ipydir 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 from IPython.Shell import IPShellEmbed
ipshell = IPShellEmbed(user_ns=user_ns) ipshell = IPShellEmbed(user_ns=user_ns)
ipshell() ipshell()

View File

@ -417,6 +417,7 @@ from calibre.devices.nokia.driver import N770, N810
from calibre.devices.eslick.driver import ESLICK from calibre.devices.eslick.driver import ESLICK
from calibre.devices.nuut2.driver import NUUT2 from calibre.devices.nuut2.driver import NUUT2
from calibre.devices.iriver.driver import IRIVER_STORY from calibre.devices.iriver.driver import IRIVER_STORY
from calibre.devices.boox.driver import BOOX
from calibre.ebooks.metadata.fetch import GoogleBooks, ISBNDB, Amazon from calibre.ebooks.metadata.fetch import GoogleBooks, ISBNDB, Amazon
plugins = [HTML2ZIP, PML2PMLZ, GoogleBooks, ISBNDB, Amazon] plugins = [HTML2ZIP, PML2PMLZ, GoogleBooks, ISBNDB, Amazon]
@ -481,6 +482,7 @@ plugins += [
ITALICA, ITALICA,
SHINEBOOK, SHINEBOOK,
ECLICTO, ECLICTO,
BOOX,
EB600, EB600,
] ]
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ plugins += [x for x in list(locals().values()) if isinstance(x, type) and \

View File

View File

@ -0,0 +1,87 @@
__license__ = 'GPL v3'
__copyright__ = '2009, Jesus Manuel Marinho Valcarce <jjjesss at gmail.com>'
__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)

View File

@ -23,6 +23,7 @@ class NOOK(USBMS):
gui_name = _('The Nook') gui_name = _('The Nook')
description = _('Communicate with the Nook eBook reader.') description = _('Communicate with the Nook eBook reader.')
author = 'John Schember' author = 'John Schember'
icon = I('devices/nook.jpg')
supported_platforms = ['windows', 'linux', 'osx'] supported_platforms = ['windows', 'linux', 'osx']
# Ordered list of supported formats # Ordered list of supported formats

View File

@ -8,6 +8,7 @@ Based on ideas from comiclrf created by FangornUK.
''' '''
import os, shutil, traceback, textwrap, time import os, shutil, traceback, textwrap, time
from ctypes import byref
from Queue import Empty from Queue import Empty
from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation
@ -75,7 +76,10 @@ class PageProcessor(list):
if img < 0: if img < 0:
raise RuntimeError('Cannot create wand.') raise RuntimeError('Cannot create wand.')
if not pw.MagickReadImage(img, self.path_to_page): 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) width = pw.MagickGetImageWidth(img)
height = pw.MagickGetImageHeight(img) height = pw.MagickGetImageHeight(img)
if self.num == 0: # First image so create a thumbnail from it if self.num == 0: # First image so create a thumbnail from it
@ -363,14 +367,14 @@ class ComicInput(InputFormatPlugin):
else: else:
new_pages, failures = process_pages(new_pages, self.opts, new_pages, failures = process_pages(new_pages, self.opts,
self.report_progress, tdir2) self.report_progress, tdir2)
if not new_pages:
raise ValueError('Could not find any valid pages in comic: %s'
% comic)
if failures: if failures:
self.log.warning('Could not process the following pages ' self.log.warning('Could not process the following pages '
'(run with --verbose to see why):') '(run with --verbose to see why):')
for f in failures: for f in failures:
self.log.warning('\t', f) 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 = os.path.join(tdir2,
'thumbnail.'+self.opts.output_format.lower()) 'thumbnail.'+self.opts.output_format.lower())
if not os.access(thumbnail, os.R_OK): if not os.access(thumbnail, os.R_OK):

View File

@ -7,7 +7,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>838</width>
<height>730</height> <height>730</height>
</rect> </rect>
</property> </property>
@ -89,7 +89,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>524</width> <width>562</width>
<height>683</height> <height>683</height>
</rect> </rect>
</property> </property>

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>335</width> <width>335</width>
<height>540</height> <height>570</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -84,104 +84,123 @@ p, li { white-space: pre-wrap; }
</item> </item>
<item> <item>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_3"> <widget class="QScrollArea" name="scrollArea">
<property name="text"> <property name="widgetResizable">
<string>Title:</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="title">
<property name="toolTip">
<string>Regular expression (?P&amp;lt;title&amp;gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Authors:</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLineEdit" name="authors">
<property name="toolTip">
<string>Regular expression (?P&lt;author&gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Series:</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QLineEdit" name="series">
<property name="toolTip">
<string>Regular expression (?P&lt;series&gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0" rowspan="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Series index:</string>
</property>
</widget>
</item>
<item row="3" column="1" rowspan="2" colspan="2">
<widget class="QLineEdit" name="series_index">
<property name="toolTip">
<string>Regular expression (?P&lt;series_index&gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>ISBN:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="isbn">
<property name="toolTip">
<string>Regular expression (?P&lt;isbn&gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool> <bool>true</bool>
</property> </property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>301</width>
<height>234</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Title:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="title">
<property name="toolTip">
<string>Regular expression (?P&amp;lt;title&amp;gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Authors:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="authors">
<property name="toolTip">
<string>Regular expression (?P&lt;author&gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Series:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="series">
<property name="toolTip">
<string>Regular expression (?P&lt;series&gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Series index:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="series_index">
<property name="toolTip">
<string>Regular expression (?P&lt;series_index&gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>ISBN:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="isbn">
<property name="toolTip">
<string>Regular expression (?P&lt;isbn&gt;)</string>
</property>
<property name="text">
<string>No match</string>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
</layout> </layout>

View File

@ -46,7 +46,10 @@ class PersistentTemporaryFile(object):
self.close() self.close()
def __del__(self): def __del__(self):
self.close() try:
self.close()
except:
pass
def PersistentTemporaryDirectory(suffix='', prefix='', dir=None): def PersistentTemporaryDirectory(suffix='', prefix='', dir=None):

View File

@ -828,7 +828,7 @@ else:
IsMagickWand = _magick.IsMagickWand IsMagickWand = _magick.IsMagickWand
# MagickGetException # MagickGetException
try: try:
_magick.MagickGetException.restype = ctypes.POINTER(ctypes.c_char) _magick.MagickGetException.restype = ctypes.c_char_p
_magick.MagickGetException.argtypes = (MagickWand,ctypes.POINTER(ExceptionType)) _magick.MagickGetException.argtypes = (MagickWand,ctypes.POINTER(ExceptionType))
except AttributeError,e: except AttributeError,e:
pass pass

View File

@ -7,6 +7,7 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import sys, os, cPickle import sys, os, cPickle
from calibre.constants import isnewosx
AUTHTOOL="""#!/usr/bin/python AUTHTOOL="""#!/usr/bin/python
import os import os
@ -27,7 +28,7 @@ for s, l in zip(scripts, links):
DEST_PATH = '/usr/bin' DEST_PATH = '/usr/bin'
def create_symlinks(): 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(): def get_scripts():
return cPickle.load(open(P('scripts.pickle'), 'rb')) return cPickle.load(open(P('scripts.pickle'), 'rb'))