mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Sync to trunk.
This commit is contained in:
commit
fd81ca32a9
BIN
resources/images/devices/nook.jpg
Normal file
BIN
resources/images/devices/nook.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
64
resources/recipes/strategy-business.recipe
Normal file
64
resources/recipes/strategy-business.recipe
Normal 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'
|
96
resources/recipes/watchingamerica.recipe
Normal file
96
resources/recipes/watchingamerica.recipe
Normal 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
|
@ -1,138 +1,17 @@
|
||||
#include "util.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";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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()
|
@ -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,23 +151,27 @@ 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):
|
||||
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()
|
||||
|
||||
@ -158,28 +188,29 @@ class Py2App(object):
|
||||
|
||||
self.add_site_packages()
|
||||
self.add_stdlib()
|
||||
self.add_resources()
|
||||
self.compile_py_modules()
|
||||
|
||||
self.create_console_app()
|
||||
|
||||
self.copy_launcher_and_site()
|
||||
self.copy_site()
|
||||
self.create_exe()
|
||||
self.thin_to_x86_64()
|
||||
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
|
||||
|
||||
|
||||
|
@ -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):
|
||||
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__)
|
||||
del m
|
||||
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()
|
||||
|
||||
|
||||
|
220
setup/installer/osx/app/util.c
Normal file
220
setup/installer/osx/app/util.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
5
setup/installer/osx/app/util.h
Normal file
5
setup/installer/osx/app/util.h
Normal 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);
|
@ -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()
|
||||
|
@ -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 \
|
||||
|
0
src/calibre/devices/boox/__init__.py
Normal file
0
src/calibre/devices/boox/__init__.py
Normal file
87
src/calibre/devices/boox/driver.py
Normal file
87
src/calibre/devices/boox/driver.py
Normal 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)
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -7,7 +7,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<width>838</width>
|
||||
<height>730</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -89,7 +89,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>524</width>
|
||||
<width>562</width>
|
||||
<height>683</height>
|
||||
</rect>
|
||||
</property>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>335</width>
|
||||
<height>540</height>
|
||||
<height>570</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -84,6 +84,21 @@ p, li { white-space: pre-wrap; }
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</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">
|
||||
@ -91,7 +106,7 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="title">
|
||||
<property name="toolTip">
|
||||
<string>Regular expression (?P&lt;title&gt;)</string>
|
||||
@ -111,7 +126,7 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="authors">
|
||||
<property name="toolTip">
|
||||
<string>Regular expression (?P<author>)</string>
|
||||
@ -131,7 +146,7 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="series">
|
||||
<property name="toolTip">
|
||||
<string>Regular expression (?P<series>)</string>
|
||||
@ -144,14 +159,14 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" rowspan="2">
|
||||
<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" rowspan="2" colspan="2">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="series_index">
|
||||
<property name="toolTip">
|
||||
<string>Regular expression (?P<series_index>)</string>
|
||||
@ -164,14 +179,14 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>ISBN:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="isbn">
|
||||
<property name="toolTip">
|
||||
<string>Regular expression (?P<isbn>)</string>
|
||||
@ -185,6 +200,10 @@ p, li { white-space: pre-wrap; }
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -46,7 +46,10 @@ class PersistentTemporaryFile(object):
|
||||
self.close()
|
||||
|
||||
def __del__(self):
|
||||
try:
|
||||
self.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def PersistentTemporaryDirectory(suffix='', prefix='', dir=None):
|
||||
|
@ -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
|
||||
|
@ -7,6 +7,7 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__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'))
|
||||
|
Loading…
x
Reference in New Issue
Block a user