rebase on recent upstream
110
Changelog.yaml
@ -4,6 +4,116 @@
|
||||
# for important features/bug fixes.
|
||||
# Also, each release can have new and improved recipes.
|
||||
|
||||
- version: 0.7.31
|
||||
date: 2010-11-27
|
||||
|
||||
bug fixes:
|
||||
- title: "Fix various regressions in the calibre windows build caused by the switch to python 2.7. If you are on windows and upgraded to 0.7.30, it is highly recommended that you upgrade to 0.7.31. If you are not on windows, you can ignore 0.7.31"
|
||||
tickets: [7685, 7694, 7691]
|
||||
|
||||
|
||||
- version: 0.7.30
|
||||
date: 2010-11-26
|
||||
|
||||
new features:
|
||||
- title: "Support for Acer Lumiread and PocketBook Pro 602"
|
||||
|
||||
- title: "When importing by ISBN also allow the specification of a file to be imported."
|
||||
tickets: [7400]
|
||||
|
||||
- title: "E-mail sending: Email sends are now regular jobs that can be accessed from the jobs list. Also when sending using gmail/hotmail send at most one email every five minutes to avoid trigerring their spam controls. Failed sends are now retried one more time, automatically."
|
||||
|
||||
- title: "Content server: When a category contains only one item, go directly to the book list instead of forcing the user to click on that one item"
|
||||
|
||||
- title: "E-mail sending: Allow unencrypted connections to SMTP relay"
|
||||
|
||||
- title: "Improve startup times for large libraries by caching the has_cover check"
|
||||
|
||||
- title: "Update windows binary build to use python 2.7"
|
||||
|
||||
- title: "Metadata and cover download plugins from Nicebooks (disabled by default)"
|
||||
|
||||
|
||||
bug fixes:
|
||||
- title: "MOBI Input: Fix bug in cleanup regex that broke parsing of escaped XML declarations."
|
||||
tickets: [7585]
|
||||
|
||||
- title: "Content server: Fix bug when user has custom categories/columns with non ascii names"
|
||||
tickets: [7590]
|
||||
|
||||
- title: "RTF Output: Handle non breaking spaces correctly"
|
||||
tickets: [7668]
|
||||
|
||||
- title: "Conversion pipeline: When rasterizing SVG images workaround incorrect handinlg of percentage height specifications in QSvgRenderer."
|
||||
tickets: [7598]
|
||||
|
||||
- title: "News download: Update version of feedparser used to parse RSS feeds."
|
||||
tickets: [7674]
|
||||
|
||||
- title: "Tag Browser: Allow user to restore hidden categories by a right click even is all categories have been hidden"
|
||||
|
||||
- title: "TXT/RTF Output: Handle XML processing instructions embedded in content correctly."
|
||||
tickets: [7644]
|
||||
|
||||
- title: "MOBI Input: Workarounds for lack of nesting rules between block and inline tags"
|
||||
tickets: [7618]
|
||||
|
||||
- title: "E-book viewer: Load all hyphenation patterns to support multi-lingual books"
|
||||
|
||||
- title: "E-book viewer: Fix incorrect lang names being used in hyphenation"
|
||||
|
||||
- title: "Check to see that the result file from a conversion is not empty before adding it, protects against the case where the conversion process crashes and the GUI adds a zero byte file to the book record"
|
||||
|
||||
- title: "E-book viewer: More sophisticated algorithm to resize images to fit viewer window. Should preserve aspect ratio in more cases"
|
||||
|
||||
- title: "Remove unneccessary calls to set_path when creating book records. Speeds up record creation by about 30% on my system"
|
||||
|
||||
- title: "Speedup for bibtex catalog generation."
|
||||
|
||||
- title: "Kobo driver: Fix missing table in deleting books process for Kobo WiFi and Kobo-O 1.8 Beta"
|
||||
|
||||
- title: "RTF Input: Preserve scene breaks in the form of empty paragraphs. Preprocessing: Improvements to chapter detection"
|
||||
|
||||
- title: "Fix custom recipe not sorted by title"
|
||||
tickets: [7486]
|
||||
|
||||
- title: "Kobo driver: Fix bug in managing the Im_Reading category on windows"
|
||||
|
||||
improved recipes:
|
||||
- "El Pais - Uruguay"
|
||||
- Argentinian La Nacion
|
||||
- comics.com
|
||||
- Mingpao
|
||||
- Revista Muy Intersante
|
||||
- Telepolis
|
||||
- New York Times
|
||||
|
||||
new recipes:
|
||||
- title: "Bangkok Biz News and Matichon"
|
||||
author: "Anat Ruangrassamee"
|
||||
|
||||
- title: "The Workingham Times and Deutsche Welle"
|
||||
author: "Darko Miletic"
|
||||
|
||||
- title: "Biz Portal"
|
||||
author: "marbs"
|
||||
|
||||
- title: "Various Japanese news sources"
|
||||
author: "Hiroshi Miura"
|
||||
|
||||
- title: "Arcamax"
|
||||
author: "Starson17"
|
||||
|
||||
- title: "Various Spanish news sources"
|
||||
author: "Gustavo Azambuja"
|
||||
|
||||
- title: "TSN"
|
||||
author: Nexus
|
||||
|
||||
- title: "Zeit Online Premium"
|
||||
author: Steffen Siebert
|
||||
|
||||
|
||||
- version: 0.7.29
|
||||
date: 2010-11-19
|
||||
|
||||
|
@ -38,6 +38,7 @@ Monocle.Browser.on = {
|
||||
iPad: navigator.userAgent.indexOf("iPad") != -1,
|
||||
BlackBerry: navigator.userAgent.indexOf("BlackBerry") != -1,
|
||||
Android: navigator.userAgent.indexOf('Android') != -1,
|
||||
MacOSX: navigator.userAgent.indexOf('Mac OS X') != -1,
|
||||
Kindle3: navigator.userAgent.match(/Kindle\/3/)
|
||||
}
|
||||
|
||||
@ -162,12 +163,23 @@ Monocle.Browser.has.transform3d = Monocle.Browser.CSSProps.isSupported([
|
||||
'OPerspective',
|
||||
'msPerspective'
|
||||
]) && Monocle.Browser.CSSProps.supportsMediaQueryProperty('transform-3d');
|
||||
Monocle.Browser.has.embedded = (top != self);
|
||||
|
||||
Monocle.Browser.has.iframeTouchBug = Monocle.Browser.iOSVersionBelow("4.2");
|
||||
|
||||
Monocle.Browser.has.selectThruBug = Monocle.Browser.iOSVersionBelow("4.2");
|
||||
|
||||
Monocle.Browser.has.mustScrollSheaf = Monocle.Browser.is.MobileSafari;
|
||||
Monocle.Browser.has.iframeDoubleWidthBug = Monocle.Browser.has.mustScrollSheaf;
|
||||
|
||||
Monocle.Browser.has.floatColumnBug = Monocle.Browser.is.WebKit;
|
||||
|
||||
Monocle.Browser.has.relativeIframeWidthBug = Monocle.Browser.on.Android;
|
||||
|
||||
|
||||
Monocle.Browser.has.jumpFlickerBug =
|
||||
Monocle.Browser.on.MacOSX && Monocle.Browser.is.WebKit;
|
||||
|
||||
|
||||
if (typeof window.console == "undefined") {
|
||||
window.console = {
|
||||
@ -1091,11 +1103,29 @@ Monocle.Reader = function (node, bookData, options, onLoadCallback) {
|
||||
cmpt.dom.setStyles(Monocle.Styles.component);
|
||||
Monocle.Styles.applyRules(cmpt.contentDocument.body, Monocle.Styles.body);
|
||||
}
|
||||
lockFrameWidths();
|
||||
dom.find('overlay').dom.setStyles(Monocle.Styles.overlay);
|
||||
dispatchEvent('monocle:styles');
|
||||
}
|
||||
|
||||
|
||||
function lockingFrameWidths() {
|
||||
if (!Monocle.Browser.has.relativeIframeWidthBug) { return; }
|
||||
for (var i = 0, cmpt; cmpt = dom.find('component', i); ++i) {
|
||||
cmpt.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function lockFrameWidths() {
|
||||
if (!Monocle.Browser.has.relativeIframeWidthBug) { return; }
|
||||
for (var i = 0, cmpt; cmpt = dom.find('component', i); ++i) {
|
||||
cmpt.style.width = cmpt.parentNode.offsetWidth+"px";
|
||||
cmpt.style.display = "block";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setBook(bk, place, callback) {
|
||||
p.book = bk;
|
||||
var pageCount = 0;
|
||||
@ -1121,12 +1151,14 @@ Monocle.Reader = function (node, bookData, options, onLoadCallback) {
|
||||
if (!p.initialized) {
|
||||
console.warn('Attempt to resize book before initialization.');
|
||||
}
|
||||
lockingFrameWidths();
|
||||
if (!dispatchEvent("monocle:resizing", {}, true)) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(p.resizeTimer);
|
||||
p.resizeTimer = setTimeout(
|
||||
function () {
|
||||
lockFrameWidths();
|
||||
p.flipper.moveTo({ page: pageNumber() });
|
||||
dispatchEvent("monocle:resize");
|
||||
},
|
||||
@ -1765,12 +1797,7 @@ Monocle.Book = function (dataSource) {
|
||||
|
||||
|
||||
function componentIdMatching(str) {
|
||||
for (var i = 0; i < p.componentIds.length; ++i) {
|
||||
if (str.indexOf(p.componentIds[i]) > -1) {
|
||||
return p.componentIds[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return p.componentIds.indexOf(str) >= 0 ? str : null;
|
||||
}
|
||||
|
||||
|
||||
@ -2018,6 +2045,12 @@ Monocle.Component = function (book, id, index, chapters, source) {
|
||||
|
||||
|
||||
function loadFrameFromURL(url, frame, callback) {
|
||||
if (!url.match(/^\//)) {
|
||||
var link = document.createElement('a');
|
||||
link.setAttribute('href', url);
|
||||
url = link.href;
|
||||
delete(link);
|
||||
}
|
||||
frame.onload = function () {
|
||||
frame.onload = null;
|
||||
Monocle.defer(callback);
|
||||
@ -2460,7 +2493,7 @@ Monocle.Flippers.Legacy = function (reader) {
|
||||
function moveTo(locus, callback) {
|
||||
var fn = frameToLocus;
|
||||
if (typeof callback == "function") {
|
||||
fn = function () { frameToLocus(); callback(); }
|
||||
fn = function (locus) { frameToLocus(locus); callback(locus); }
|
||||
}
|
||||
p.reader.getBook().setOrLoadPageAt(page(), locus, fn);
|
||||
}
|
||||
@ -2794,7 +2827,9 @@ Monocle.Dimensions.Columns = function (pageDiv) {
|
||||
function scrollerWidth() {
|
||||
var bdy = p.page.m.activeFrame.contentDocument.body;
|
||||
if (Monocle.Browser.has.iframeDoubleWidthBug) {
|
||||
if (Monocle.Browser.iOSVersion < "4.1") {
|
||||
if (Monocle.Browser.on.Android) {
|
||||
return bdy.scrollWidth * 1.5; // I actually have no idea why 1.5.
|
||||
} else if (Monocle.Browser.iOSVersion < "4.1") {
|
||||
var hbw = bdy.scrollWidth / 2;
|
||||
var sew = scrollerElement().scrollWidth;
|
||||
return Math.max(sew, hbw);
|
||||
@ -2969,6 +3004,7 @@ Monocle.Flippers.Slider = function (reader) {
|
||||
|
||||
|
||||
function setPage(pageDiv, locus, callback) {
|
||||
ensureWaitControl();
|
||||
p.reader.getBook().setOrLoadPageAt(
|
||||
pageDiv,
|
||||
locus,
|
||||
@ -3048,6 +3084,7 @@ Monocle.Flippers.Slider = function (reader) {
|
||||
checkPoint(boxPointX);
|
||||
|
||||
p.turnData.releasing = true;
|
||||
showWaitControl(lowerPage());
|
||||
|
||||
if (dir == k.FORWARDS) {
|
||||
if (
|
||||
@ -3088,14 +3125,18 @@ Monocle.Flippers.Slider = function (reader) {
|
||||
|
||||
|
||||
function onGoingBackward(x) {
|
||||
var lp = lowerPage();
|
||||
var lp = lowerPage(), up = upperPage();
|
||||
showWaitControl(up);
|
||||
jumpOut(lp, // move lower page off-screen
|
||||
function () {
|
||||
flipPages(); // flip lower to upper
|
||||
setPage( // set upper page to previous
|
||||
lp,
|
||||
getPlace(lowerPage()).getLocus({ direction: k.BACKWARDS }),
|
||||
function () { lifted(x); }
|
||||
function () {
|
||||
lifted(x);
|
||||
hideWaitControl(up);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
@ -3103,8 +3144,10 @@ Monocle.Flippers.Slider = function (reader) {
|
||||
|
||||
|
||||
function afterGoingForward() {
|
||||
var up = upperPage();
|
||||
var up = upperPage(), lp = lowerPage();
|
||||
if (p.interactive) {
|
||||
showWaitControl(up);
|
||||
showWaitControl(lp);
|
||||
setPage( // set upper (off screen) to current
|
||||
up,
|
||||
getPlace().getLocus({ direction: k.FORWARDS }),
|
||||
@ -3113,6 +3156,7 @@ Monocle.Flippers.Slider = function (reader) {
|
||||
}
|
||||
);
|
||||
} else {
|
||||
showWaitControl(lp);
|
||||
flipPages();
|
||||
jumpIn(up, function () { prepareNextPage(announceTurn); });
|
||||
}
|
||||
@ -3171,6 +3215,8 @@ Monocle.Flippers.Slider = function (reader) {
|
||||
|
||||
|
||||
function announceTurn() {
|
||||
hideWaitControl(upperPage());
|
||||
hideWaitControl(lowerPage());
|
||||
p.reader.dispatchEvent('monocle:turn');
|
||||
resetTurnData();
|
||||
}
|
||||
@ -3319,12 +3365,14 @@ Monocle.Flippers.Slider = function (reader) {
|
||||
|
||||
|
||||
function jumpIn(pageDiv, callback) {
|
||||
setX(pageDiv, 0, { duration: 1 }, callback);
|
||||
var dur = Monocle.Browser.has.jumpFlickerBug ? 1 : 0;
|
||||
setX(pageDiv, 0, { duration: dur }, callback);
|
||||
}
|
||||
|
||||
|
||||
function jumpOut(pageDiv, callback) {
|
||||
setX(pageDiv, 0 - pageDiv.offsetWidth, { duration: 1 }, callback);
|
||||
var dur = Monocle.Browser.has.jumpFlickerBug ? 1 : 0;
|
||||
setX(pageDiv, 0 - pageDiv.offsetWidth, { duration: dur }, callback);
|
||||
}
|
||||
|
||||
|
||||
@ -3357,6 +3405,28 @@ Monocle.Flippers.Slider = function (reader) {
|
||||
}
|
||||
|
||||
|
||||
function ensureWaitControl() {
|
||||
if (p.waitControl) { return; }
|
||||
p.waitControl = {
|
||||
createControlElements: function (holder) {
|
||||
return holder.dom.make('div', 'flippers_slider_wait');
|
||||
}
|
||||
}
|
||||
p.reader.addControl(p.waitControl, 'page');
|
||||
}
|
||||
|
||||
|
||||
function showWaitControl(page) {
|
||||
var ctrl = p.reader.dom.find('flippers_slider_wait', page.m.pageIndex);
|
||||
ctrl.style.opacity = 0.5;
|
||||
}
|
||||
|
||||
|
||||
function hideWaitControl(page) {
|
||||
var ctrl = p.reader.dom.find('flippers_slider_wait', page.m.pageIndex);
|
||||
ctrl.style.opacity = 0;
|
||||
}
|
||||
|
||||
API.pageCount = p.pageCount;
|
||||
API.addPage = addPage;
|
||||
API.getPlace = getPlace;
|
||||
|
BIN
resources/images/news/deutsche_welle_bs.png
Normal file
After Width: | Height: | Size: 445 B |
BIN
resources/images/news/deutsche_welle_en.png
Normal file
After Width: | Height: | Size: 445 B |
BIN
resources/images/news/deutsche_welle_es.png
Normal file
After Width: | Height: | Size: 445 B |
BIN
resources/images/news/deutsche_welle_hr.png
Normal file
After Width: | Height: | Size: 445 B |
BIN
resources/images/news/deutsche_welle_pt.png
Normal file
After Width: | Height: | Size: 445 B |
BIN
resources/images/news/deutsche_welle_sr.png
Normal file
After Width: | Height: | Size: 445 B |
BIN
resources/images/news/the_workingham_times.png
Normal file
After Width: | Height: | Size: 1011 B |
111
resources/recipes/animal_politico.recipe
Normal file
@ -0,0 +1,111 @@
|
||||
#!/usr/bin/python
|
||||
# encoding: utf-8
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1290663986(BasicNewsRecipe):
|
||||
title = u'Animal Pol\u00EDtico'
|
||||
publisher = u'Animal Pol\u00EDtico'
|
||||
category = u'News, Mexico'
|
||||
description = u'Noticias Pol\u00EDticas'
|
||||
__author__ = 'leamsi'
|
||||
masthead_url = 'http://www.animalpolitico.com/wp-content/themes/animal_mu/images/logo.png'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
language = 'es'
|
||||
|
||||
#feeds = [(u'Animal Politico', u'http://www.animalpolitico.com/feed/')]
|
||||
|
||||
remove_tags_before = dict(name='div', id='main')
|
||||
remove_tags = [dict(name='div', attrs={'class':'fb-like-button'})]
|
||||
keep_only_tags = [dict(name='h1', attrs={'class':'entry-title'}),
|
||||
dict(name='div', attrs={'class':'entry-content'})]
|
||||
remove_javascript = True
|
||||
INDEX = 'http://www.animalpolitico.com/'
|
||||
|
||||
def generic_parse(self, soup):
|
||||
articles = []
|
||||
for entry in soup.findAll(lambda tag: tag.name == 'li' and tag.has_key('class') and tag['class'].find('hentry') != -1): #soup.findAll('li', 'hentry'):
|
||||
article_url = entry.a['href'] + '?print=yes'
|
||||
article_title= entry.find('h3', 'entry-title')
|
||||
article_title= self.tag_to_string(article_title)
|
||||
article_date = entry.find('span', 'the-time')
|
||||
article_date = self.tag_to_string(article_date)
|
||||
article_desc = self.tag_to_string(entry.find('p'))
|
||||
|
||||
#print 'Article:',article_title, article_date,article_url
|
||||
#print entry['class']
|
||||
|
||||
articles.append({'title' : article_title,
|
||||
'date' : article_date,
|
||||
'description' : article_desc,
|
||||
'url' : article_url})
|
||||
# Avoid including the multimedia stuff.
|
||||
if entry['class'].find('last') != -1:
|
||||
break
|
||||
|
||||
return articles
|
||||
|
||||
def plumaje_parse(self, soup):
|
||||
articles = []
|
||||
blogs_soup = soup.find(lambda tag: tag.name == 'ul' and tag.has_key('class') and tag['class'].find('bloglist-fecha') != -1)
|
||||
for entry in blogs_soup.findAll('li'):
|
||||
article_title = entry.p
|
||||
article_url = article_title.a['href'] + '?print=yes'
|
||||
article_date = article_title.nextSibling
|
||||
article_title = self.tag_to_string(article_title)
|
||||
article_date = self.tag_to_string(article_date).replace(u'Last Updated: ', '')
|
||||
article_desc = self.tag_to_string(entry.find('h4'))
|
||||
|
||||
#print 'Article:',article_title, article_date,article_url
|
||||
articles.append({'title' : article_title,
|
||||
'date' : article_date,
|
||||
'description' : article_desc,
|
||||
'url' : article_url})
|
||||
|
||||
return articles
|
||||
|
||||
def boca_parse(self, soup):
|
||||
articles = []
|
||||
for entry in soup.findAll(lambda tag: tag.name == 'div' and tag.has_key('class') and tag['class'].find('hentry') != -1): #soup.findAll('li', 'hentry'):
|
||||
article_title= entry.find('h2', 'entry-title')
|
||||
article_url = article_title.a['href'] + '?print=yes'
|
||||
article_title= self.tag_to_string(article_title)
|
||||
article_date = entry.find('span', 'entry-date')
|
||||
article_date = self.tag_to_string(article_date)
|
||||
article_desc = self.tag_to_string(entry.find('div', 'entry-content'))
|
||||
|
||||
#print 'Article:',article_title, article_date,article_url
|
||||
#print entry['class']
|
||||
|
||||
articles.append({'title' : article_title,
|
||||
'date' : article_date,
|
||||
'description' : article_desc,
|
||||
'url' : article_url})
|
||||
# Avoid including the multimedia stuff.
|
||||
if entry['class'].find('last') != -1:
|
||||
break
|
||||
|
||||
return articles
|
||||
|
||||
|
||||
|
||||
|
||||
def parse_index(self):
|
||||
gobierno_soup = self.index_to_soup(self.INDEX+'gobierno/')
|
||||
congreso_soup = self.index_to_soup(self.INDEX+'congreso/')
|
||||
seguridad_soup = self.index_to_soup(self.INDEX+'seguridad/')
|
||||
comunidad_soup = self.index_to_soup(self.INDEX+'comunidad/')
|
||||
plumaje_soup = self.index_to_soup(self.INDEX+'plumaje/')
|
||||
la_boca_del_lobo_soup = self.index_to_soup(self.INDEX+'category/la-boca-del-lobo/')
|
||||
|
||||
gobierno_articles = self.generic_parse(gobierno_soup)
|
||||
congreso_articles = self.generic_parse(congreso_soup)
|
||||
seguridad_articles = self.generic_parse(seguridad_soup)
|
||||
comunidad_articles = self.generic_parse(comunidad_soup)
|
||||
plumaje_articles = self.plumaje_parse(plumaje_soup)
|
||||
la_boca_del_lobo_articles = self.boca_parse(la_boca_del_lobo_soup)
|
||||
|
||||
|
||||
return [ (u'Gobierno', gobierno_articles), (u'Congreso', congreso_articles), (u'Seguridad', seguridad_articles),
|
||||
(u'Comunidad', comunidad_articles), (u'Plumaje', plumaje_articles), (u'La Boca del Lobo', la_boca_del_lobo_articles), ]
|
110
resources/recipes/arcamax.recipe
Normal file
@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = 'Copyright 2010 Starson17'
|
||||
'''
|
||||
www.arcamax.com
|
||||
'''
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class Arcamax(BasicNewsRecipe):
|
||||
title = 'Arcamax'
|
||||
__author__ = 'Starson17'
|
||||
__version__ = '1.03'
|
||||
__date__ = '25 November 2010'
|
||||
description = u'Family Friendly Comics - Customize for more days/comics: Defaults to 7 days, 25 comics - 20 general, 5 editorial.'
|
||||
category = 'news, comics'
|
||||
language = 'en'
|
||||
use_embedded_content= False
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
cover_url = 'http://www.arcamax.com/images/pub/amuse/leftcol/zits.jpg'
|
||||
|
||||
####### USER PREFERENCES - SET COMICS AND NUMBER OF COMICS TO RETRIEVE ########
|
||||
num_comics_to_get = 7
|
||||
# CHOOSE COMIC STRIPS BELOW - REMOVE COMMENT '# ' FROM IN FRONT OF DESIRED STRIPS
|
||||
|
||||
conversion_options = {'linearize_tables' : True
|
||||
, 'comment' : description
|
||||
, 'tags' : category
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'class':['toon']}),
|
||||
]
|
||||
|
||||
def parse_index(self):
|
||||
feeds = []
|
||||
for title, url in [
|
||||
######## COMICS - GENERAL ########
|
||||
#(u"9 Chickweed Lane", u"http://www.arcamax.com/ninechickweedlane"),
|
||||
#(u"Agnes", u"http://www.arcamax.com/agnes"),
|
||||
#(u"Andy Capp", u"http://www.arcamax.com/andycapp"),
|
||||
(u"BC", u"http://www.arcamax.com/bc"),
|
||||
#(u"Baby Blues", u"http://www.arcamax.com/babyblues"),
|
||||
#(u"Beetle Bailey", u"http://www.arcamax.com/beetlebailey"),
|
||||
(u"Blondie", u"http://www.arcamax.com/blondie"),
|
||||
#u"Boondocks", u"http://www.arcamax.com/boondocks"),
|
||||
#(u"Cathy", u"http://www.arcamax.com/cathy"),
|
||||
#(u"Daddys Home", u"http://www.arcamax.com/daddyshome"),
|
||||
(u"Dilbert", u"http://www.arcamax.com/dilbert"),
|
||||
#(u"Dinette Set", u"http://www.arcamax.com/thedinetteset"),
|
||||
(u"Dog Eat Doug", u"http://www.arcamax.com/dogeatdoug"),
|
||||
(u"Doonesbury", u"http://www.arcamax.com/doonesbury"),
|
||||
#(u"Dustin", u"http://www.arcamax.com/dustin"),
|
||||
(u"Family Circus", u"http://www.arcamax.com/familycircus"),
|
||||
(u"Garfield", u"http://www.arcamax.com/garfield"),
|
||||
#(u"Get Fuzzy", u"http://www.arcamax.com/getfuzzy"),
|
||||
#(u"Girls and Sports", u"http://www.arcamax.com/girlsandsports"),
|
||||
#(u"Hagar the Horrible", u"http://www.arcamax.com/hagarthehorrible"),
|
||||
#(u"Heathcliff", u"http://www.arcamax.com/heathcliff"),
|
||||
#(u"Jerry King Cartoons", u"http://www.arcamax.com/humorcartoon"),
|
||||
#(u"Luann", u"http://www.arcamax.com/luann"),
|
||||
#(u"Momma", u"http://www.arcamax.com/momma"),
|
||||
#(u"Mother Goose and Grimm", u"http://www.arcamax.com/mothergooseandgrimm"),
|
||||
(u"Mutts", u"http://www.arcamax.com/mutts"),
|
||||
#(u"Non Sequitur", u"http://www.arcamax.com/nonsequitur"),
|
||||
#(u"Pearls Before Swine", u"http://www.arcamax.com/pearlsbeforeswine"),
|
||||
#(u"Pickles", u"http://www.arcamax.com/pickles"),
|
||||
#(u"Red and Rover", u"http://www.arcamax.com/redandrover"),
|
||||
#(u"Rubes", u"http://www.arcamax.com/rubes"),
|
||||
#(u"Rugrats", u"http://www.arcamax.com/rugrats"),
|
||||
(u"Speed Bump", u"http://www.arcamax.com/speedbump"),
|
||||
(u"Wizard of Id", u"http://www.arcamax.com/wizardofid"),
|
||||
(u"Dilbert", u"http://www.arcamax.com/dilbert"),
|
||||
(u"Zits", u"http://www.arcamax.com/zits"),
|
||||
]:
|
||||
articles = self.make_links(url)
|
||||
if articles:
|
||||
feeds.append((title, articles))
|
||||
return feeds
|
||||
|
||||
def make_links(self, url):
|
||||
title = 'Temp'
|
||||
current_articles = []
|
||||
pages = range(1, self.num_comics_to_get+1)
|
||||
for page in pages:
|
||||
page_soup = self.index_to_soup(url)
|
||||
if page_soup:
|
||||
title = page_soup.find(name='div', attrs={'class':'toon'}).p.img['alt']
|
||||
page_url = url
|
||||
prev_page_url = 'http://www.arcamax.com' + page_soup.find('a', attrs={'class':'next'}, text='Previous').parent['href']
|
||||
current_articles.append({'title': title, 'url': page_url, 'description':'', 'date':''})
|
||||
url = prev_page_url
|
||||
current_articles.reverse()
|
||||
return current_articles
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
main_comic = soup.find('p',attrs={'class':'m0'})
|
||||
if main_comic.a['target'] == '_blank':
|
||||
main_comic.a.img['id'] = 'main_comic'
|
||||
return soup
|
||||
|
||||
extra_css = '''
|
||||
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
|
||||
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
|
||||
img#main_comic {max-width:100%; min-width:100%;}
|
||||
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
|
||||
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
|
||||
'''
|
||||
|
25
resources/recipes/bangkok_biz.recipe
Normal file
@ -0,0 +1,25 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1290689337(BasicNewsRecipe):
|
||||
__author__ = 'Anat R.'
|
||||
language = 'th'
|
||||
title = u'Bangkok Biz News'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
use_embedded_content = False
|
||||
feeds = [(u'Headlines',
|
||||
u'http://www.bangkokbiznews.com/home/services/rss/home.xml'),
|
||||
(u'Politics', u'http://www.bangkokbiznews.com/home/services/rss/politics.xml'),
|
||||
(u'Business', u'http://www.bangkokbiznews.com/home/services/rss/business.xml'),
|
||||
(u'Finance', u' http://www.bangkokbiznews.com/home/services/rss/finance.xml'),
|
||||
(u'Technology', u' http://www.bangkokbiznews.com/home/services/rss/it.xml')]
|
||||
remove_tags_before = dict(name='div', attrs={'class':'box-Detailcontent'})
|
||||
remove_tags_after = dict(name='p', attrs={'class':'allTags'})
|
||||
remove_tags = []
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id': 'content-tools'}))
|
||||
remove_tags.append(dict(name = 'p', attrs = {'class':'allTags'}))
|
||||
remove_tags.append(dict(name = 'div', attrs = {'id':'morePic'}))
|
||||
remove_tags.append(dict(name = 'ul', attrs = {'class':'tabs-nav'}))
|
||||
|
40
resources/recipes/biz_portal.recipe
Normal file
@ -0,0 +1,40 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1283848012(BasicNewsRecipe):
|
||||
description = 'This is a recipe of BizPortal.co.il.'
|
||||
cover_url = 'http://www.bizportal.co.il/shukhahon/images/bizportal.jpg'
|
||||
title = u'BizPortal'
|
||||
language = 'he'
|
||||
__author__ = 'marbs'
|
||||
extra_css='img {max-width:100%;} body{direction: rtl;},title{direction: rtl; } ,article_description{direction: rtl; }, a.article{direction: rtl; } ,calibre_feed_description{direction: rtl; }'
|
||||
simultaneous_downloads = 5
|
||||
remove_javascript = True
|
||||
timefmt = '[%a, %d %b, %Y]'
|
||||
remove_empty_feeds = True
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
remove_attributes = ['width']
|
||||
simultaneous_downloads = 5
|
||||
# keep_only_tags =dict(name='div', attrs={'id':'articleContainer'})
|
||||
remove_tags = [dict(name='img', attrs={'scr':['images/bizlogo_nl.gif']})]
|
||||
max_articles_per_feed = 100
|
||||
#preprocess_regexps = [
|
||||
# (re.compile(r'<p> </p>', re.DOTALL|re.IGNORECASE), lambda match: '')
|
||||
# ]
|
||||
|
||||
|
||||
feeds = [(u'חדשות שוק ההון', u'http://www.bizportal.co.il/shukhahon/messRssUTF2.xml'),
|
||||
(u'חדשות וול סטריט בעברית', u'http://www.bizportal.co.il/shukhahon/images/bizportal.jpg'),
|
||||
(u'שיווק ופרסום', u'http://www.bizportal.co.il/shukhahon/messRssUTF145.xml'),
|
||||
(u'משפט', u'http://www.bizportal.co.il/shukhahon/messRssUTF3.xml'),
|
||||
(u'ניתוח טכני', u'http://www.bizportal.co.il/shukhahon/messRssUTF5.xml'),
|
||||
(u'דיני עבודה ושכר', u'http://www.bizportal.co.il/shukhahon/messRssUTF6.xml'),
|
||||
(u'מיסוי', u'http://www.bizportal.co.il/shukhahon/messRssUTF7.xml'),
|
||||
(u'טאבו', u'http://www.bizportal.co.il/shukhahon/messRssUTF8.xml'),
|
||||
(u'נדל"ן', u'http://www.bizportal.co.il/shukhahon/messRssUTF160.xml'),
|
||||
]
|
||||
|
||||
def print_version(self, url):
|
||||
split1 = url.split("=")
|
||||
print_url = 'http://www.bizportal.co.il/web/webnew/shukhahon/biznews02print.shtml?mid=' + split1[1]
|
||||
return print_url
|
@ -27,7 +27,7 @@ class BrandEins(BasicNewsRecipe):
|
||||
encoding = 'utf-8'
|
||||
language = 'de'
|
||||
publication_type = 'magazine'
|
||||
needs_subscription = True
|
||||
needs_subscription = 'optional'
|
||||
|
||||
# 2 is the last full magazine (default)
|
||||
# 1 is the newest (but not full)
|
||||
|
@ -11,7 +11,6 @@ class AdvancedUserRecipe1275798572(BasicNewsRecipe):
|
||||
remove_javascript = True
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'en'
|
||||
masthead_url = 'http://www.cbc.ca/includes/gfx/cbcnews_logo_09.gif'
|
||||
cover_url = 'http://img692.imageshack.us/img692/2814/cbc.png'
|
||||
keep_only_tags = [dict(name='div', attrs={'id':['storyhead','storybody']})]
|
||||
|
@ -347,6 +347,7 @@ class Comics(BasicNewsRecipe):
|
||||
title = strip_tag['title']
|
||||
print 'title: ', title
|
||||
current_articles.append({'title': title, 'url': page_url, 'description':'', 'date':''})
|
||||
current_articles.reverse()
|
||||
return current_articles
|
||||
|
||||
extra_css = '''
|
||||
|
76
resources/recipes/deutsche_welle_bs.recipe
Normal file
@ -0,0 +1,76 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
dw-world.de
|
||||
'''
|
||||
|
||||
import re
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class DeutscheWelle_bs(BasicNewsRecipe):
|
||||
title = 'Deutsche Welle'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'Vijesti iz Njemacke i svijeta'
|
||||
publisher = 'Deutsche Welle'
|
||||
category = 'news, politics, Germany'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'bs'
|
||||
publication_type = 'newsportal'
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.dw-world.de/skins/std/channel1/pics/dw_logo1024.gif'
|
||||
extra_css = """
|
||||
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
|
||||
body{font-family: Arial,sans1,sans-serif}
|
||||
img{margin-top: 0.5em; margin-bottom: 0.2em; display: block}
|
||||
.caption{font-size: x-small; display: block; margin-bottom: 0.4em}
|
||||
"""
|
||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher': publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
remove_tags = [
|
||||
dict(name=['iframe','embed','object','form','base','meta','link'])
|
||||
,dict(attrs={'class':'actionFooter'})
|
||||
]
|
||||
keep_only_tags=[dict(attrs={'class':'ArticleDetail detail'})]
|
||||
remove_attributes = ['height','width','onclick','border','lang']
|
||||
|
||||
feeds = [
|
||||
(u'Politika' , u'http://rss.dw-world.de/rdf/rss-bos-pol')
|
||||
,(u'Evropa' , u'http://rss.dw-world.de/rdf/rss-bos-eu' )
|
||||
,(u'Kiosk' , u'http://rss.dw-world.de/rdf/rss-bos-eu' )
|
||||
,(u'Ekonomija i Nuka' , u'http://rss.dw-world.de/rdf/rss-bos-eco')
|
||||
,(u'Kultura' , u'http://rss.dw-world.de/rdf/rss-bos-cul')
|
||||
,(u'Sport' , u'http://rss.dw-world.de/rdf/rss-bos-sp' )
|
||||
]
|
||||
|
||||
def print_version(self, url):
|
||||
artl = url.rpartition('/')[2]
|
||||
return 'http://www.dw-world.de/popups/popup_printcontent/' + artl
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll('a'):
|
||||
limg = item.find('img')
|
||||
if item.string is not None:
|
||||
str = item.string
|
||||
item.replaceWith(str)
|
||||
else:
|
||||
if limg:
|
||||
item.name = 'div'
|
||||
del item['href']
|
||||
if item.has_key('target'):
|
||||
del item['target']
|
||||
else:
|
||||
str = self.tag_to_string(item)
|
||||
item.replaceWith(str)
|
||||
return soup
|
||||
|
66
resources/recipes/deutsche_welle_en.recipe
Normal file
@ -0,0 +1,66 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
dw-world.de
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class DeutscheWelle_en(BasicNewsRecipe):
|
||||
title = 'Deutsche Welle'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'News from Germany and World'
|
||||
publisher = 'Deutsche Welle'
|
||||
category = 'news, politics, Germany'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'en'
|
||||
publication_type = 'newsportal'
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.dw-world.de/skins/std/channel1/pics/dw_logo1024.gif'
|
||||
extra_css = """
|
||||
body{font-family: Arial,sans-serif}
|
||||
img{margin-top: 0.5em; margin-bottom: 0.2em; display: block}
|
||||
.caption{font-size: x-small; display: block; margin-bottom: 0.4em}
|
||||
"""
|
||||
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher': publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
remove_tags = [
|
||||
dict(name=['iframe','embed','object','form','base','meta','link'])
|
||||
,dict(attrs={'class':'actionFooter'})
|
||||
]
|
||||
keep_only_tags=[dict(attrs={'class':'ArticleDetail detail'})]
|
||||
remove_attributes = ['height','width','onclick','border','lang']
|
||||
|
||||
feeds = [(u'All news', u'http://rss.dw-world.de/rdf/rss-en-all')]
|
||||
|
||||
def print_version(self, url):
|
||||
artl = url.rpartition('/')[2]
|
||||
return 'http://www.dw-world.de/popups/popup_printcontent/' + artl
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll('a'):
|
||||
limg = item.find('img')
|
||||
if item.string is not None:
|
||||
str = item.string
|
||||
item.replaceWith(str)
|
||||
else:
|
||||
if limg:
|
||||
item.name = 'div'
|
||||
del item['href']
|
||||
if item.has_key('target'):
|
||||
del item['target']
|
||||
else:
|
||||
str = self.tag_to_string(item)
|
||||
item.replaceWith(str)
|
||||
return soup
|
||||
|
66
resources/recipes/deutsche_welle_es.recipe
Normal file
@ -0,0 +1,66 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
dw-world.de
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class DeutscheWelle_es(BasicNewsRecipe):
|
||||
title = 'Deutsche Welle'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'Noticias desde Alemania y mundo'
|
||||
publisher = 'Deutsche Welle'
|
||||
category = 'news, politics, Germany'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'es'
|
||||
publication_type = 'newsportal'
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.dw-world.de/skins/std/channel1/pics/dw_logo1024.gif'
|
||||
extra_css = """
|
||||
body{font-family: Arial,sans-serif}
|
||||
img{margin-top: 0.5em; margin-bottom: 0.2em; display: block}
|
||||
.caption{font-size: x-small; display: block; margin-bottom: 0.4em}
|
||||
"""
|
||||
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher': publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
remove_tags = [
|
||||
dict(name=['iframe','embed','object','form','base','meta','link'])
|
||||
,dict(attrs={'class':'actionFooter'})
|
||||
]
|
||||
keep_only_tags=[dict(attrs={'class':'ArticleDetail detail'})]
|
||||
remove_attributes = ['height','width','onclick','border','lang']
|
||||
|
||||
feeds = [(u'Noticias', u'http://rss.dw-world.de/rdf/rss-sp-all')]
|
||||
|
||||
def print_version(self, url):
|
||||
artl = url.rpartition('/')[2]
|
||||
return 'http://www.dw-world.de/popups/popup_printcontent/' + artl
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll('a'):
|
||||
limg = item.find('img')
|
||||
if item.string is not None:
|
||||
str = item.string
|
||||
item.replaceWith(str)
|
||||
else:
|
||||
if limg:
|
||||
item.name = 'div'
|
||||
del item['href']
|
||||
if item.has_key('target'):
|
||||
del item['target']
|
||||
else:
|
||||
str = self.tag_to_string(item)
|
||||
item.replaceWith(str)
|
||||
return soup
|
||||
|
74
resources/recipes/deutsche_welle_hr.recipe
Normal file
@ -0,0 +1,74 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
dw-world.de
|
||||
'''
|
||||
|
||||
import re
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class DeutscheWelle_hr(BasicNewsRecipe):
|
||||
title = 'Deutsche Welle'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'Vesti iz Njemacke i svijeta'
|
||||
publisher = 'Deutsche Welle'
|
||||
category = 'news, politics, Germany'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'hr'
|
||||
publication_type = 'newsportal'
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.dw-world.de/skins/std/channel1/pics/dw_logo1024.gif'
|
||||
extra_css = """
|
||||
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
|
||||
body{font-family: Arial,sans1,sans-serif}
|
||||
img{margin-top: 0.5em; margin-bottom: 0.2em; display: block}
|
||||
.caption{font-size: x-small; display: block; margin-bottom: 0.4em}
|
||||
"""
|
||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher': publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
remove_tags = [
|
||||
dict(name=['iframe','embed','object','form','base','meta','link'])
|
||||
,dict(attrs={'class':'actionFooter'})
|
||||
]
|
||||
keep_only_tags=[dict(attrs={'class':'ArticleDetail detail'})]
|
||||
remove_attributes = ['height','width','onclick','border','lang']
|
||||
|
||||
feeds = [
|
||||
(u'Svijet' , u'http://rss.dw-world.de/rdf/rss-cro-svijet')
|
||||
,(u'Europa' , u'http://rss.dw-world.de/rdf/rss-cro-eu' )
|
||||
,(u'Njemacka' , u'http://rss.dw-world.de/rdf/rss-cro-ger' )
|
||||
,(u'Vijesti' , u'http://rss.dw-world.de/rdf/rss-cro-all' )
|
||||
]
|
||||
|
||||
def print_version(self, url):
|
||||
artl = url.rpartition('/')[2]
|
||||
return 'http://www.dw-world.de/popups/popup_printcontent/' + artl
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll('a'):
|
||||
limg = item.find('img')
|
||||
if item.string is not None:
|
||||
str = item.string
|
||||
item.replaceWith(str)
|
||||
else:
|
||||
if limg:
|
||||
item.name = 'div'
|
||||
del item['href']
|
||||
if item.has_key('target'):
|
||||
del item['target']
|
||||
else:
|
||||
str = self.tag_to_string(item)
|
||||
item.replaceWith(str)
|
||||
return soup
|
||||
|
66
resources/recipes/deutsche_welle_pt.recipe
Normal file
@ -0,0 +1,66 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
dw-world.de
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class DeutscheWelle_pt(BasicNewsRecipe):
|
||||
title = 'Deutsche Welle'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'Noticias desde Alemania y mundo'
|
||||
publisher = 'Deutsche Welle'
|
||||
category = 'news, politics, Germany'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'pt'
|
||||
publication_type = 'newsportal'
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.dw-world.de/skins/std/channel1/pics/dw_logo1024.gif'
|
||||
extra_css = """
|
||||
body{font-family: Arial,sans-serif}
|
||||
img{margin-top: 0.5em; margin-bottom: 0.2em; display: block}
|
||||
.caption{font-size: x-small; display: block; margin-bottom: 0.4em}
|
||||
"""
|
||||
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher': publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
remove_tags = [
|
||||
dict(name=['iframe','embed','object','form','base','meta','link'])
|
||||
,dict(attrs={'class':'actionFooter'})
|
||||
]
|
||||
keep_only_tags=[dict(attrs={'class':'ArticleDetail detail'})]
|
||||
remove_attributes = ['height','width','onclick','border','lang']
|
||||
|
||||
feeds = [(u'Noticias', u'http://rss.dw-world.de/rdf/rss-br-all')]
|
||||
|
||||
def print_version(self, url):
|
||||
artl = url.rpartition('/')[2]
|
||||
return 'http://www.dw-world.de/popups/popup_printcontent/' + artl
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll('a'):
|
||||
limg = item.find('img')
|
||||
if item.string is not None:
|
||||
str = item.string
|
||||
item.replaceWith(str)
|
||||
else:
|
||||
if limg:
|
||||
item.name = 'div'
|
||||
del item['href']
|
||||
if item.has_key('target'):
|
||||
del item['target']
|
||||
else:
|
||||
str = self.tag_to_string(item)
|
||||
item.replaceWith(str)
|
||||
return soup
|
||||
|
79
resources/recipes/deutsche_welle_sr.recipe
Normal file
@ -0,0 +1,79 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
dw-world.de
|
||||
'''
|
||||
|
||||
import re
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class DeutscheWelle_sr(BasicNewsRecipe):
|
||||
title = 'Deutsche Welle'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'Vesti iz Nemacke i sveta'
|
||||
publisher = 'Deutsche Welle'
|
||||
category = 'news, politics, Germany'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 100
|
||||
use_embedded_content = False
|
||||
no_stylesheets = True
|
||||
language = 'sr'
|
||||
publication_type = 'newsportal'
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.dw-world.de/skins/std/channel1/pics/dw_logo1024.gif'
|
||||
extra_css = """
|
||||
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
|
||||
body{font-family: Arial,sans1,sans-serif}
|
||||
img{margin-top: 0.5em; margin-bottom: 0.2em; display: block}
|
||||
.caption{font-size: x-small; display: block; margin-bottom: 0.4em}
|
||||
"""
|
||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher': publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
remove_tags = [
|
||||
dict(name=['iframe','embed','object','form','base','meta','link'])
|
||||
,dict(attrs={'class':'actionFooter'})
|
||||
]
|
||||
keep_only_tags=[dict(attrs={'class':'ArticleDetail detail'})]
|
||||
remove_attributes = ['height','width','onclick','border','lang']
|
||||
|
||||
feeds = [
|
||||
(u'Politika' , u'http://rss.dw-world.de/rdf/rss-ser-pol' )
|
||||
,(u'Srbija' , u'http://rss.dw-world.de/rdf/rss-ser-pol-ser' )
|
||||
,(u'Region' , u'http://rss.dw-world.de/rdf/rss-ser-pol-region' )
|
||||
,(u'Evropa' , u'http://rss.dw-world.de/rdf/rss-ser-pol-eu' )
|
||||
,(u'Nemacka' , u'http://rss.dw-world.de/rdf/rss-ser-pol-ger' )
|
||||
,(u'Svet' , u'http://rss.dw-world.de/rdf/rss-ser-pol-ger' )
|
||||
,(u'Pregled stampe', u'http://rss.dw-world.de/rdf/rss-ser-pol-ger')
|
||||
,(u'Nauka Tehnika Medicina', u'http://rss.dw-world.de/rdf/rss-ser-science')
|
||||
,(u'Kultura' , u'feed:http://rss.dw-world.de/rdf/rss-ser-cul' )
|
||||
]
|
||||
|
||||
def print_version(self, url):
|
||||
artl = url.rpartition('/')[2]
|
||||
return 'http://www.dw-world.de/popups/popup_printcontent/' + artl
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll('a'):
|
||||
limg = item.find('img')
|
||||
if item.string is not None:
|
||||
str = item.string
|
||||
item.replaceWith(str)
|
||||
else:
|
||||
if limg:
|
||||
item.name = 'div'
|
||||
del item['href']
|
||||
if item.has_key('target'):
|
||||
del item['target']
|
||||
else:
|
||||
str = self.tag_to_string(item)
|
||||
item.replaceWith(str)
|
||||
return soup
|
||||
|
@ -9,23 +9,34 @@ http://www.elpais.com.uy/
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class General(BasicNewsRecipe):
|
||||
title = 'Diario El Pais'
|
||||
title = 'El Pais - Uruguay'
|
||||
__author__ = 'Gustavo Azambuja'
|
||||
description = 'Noticias | Uruguay'
|
||||
description = 'Noticias de Uruguay y el resto del mundo'
|
||||
publisher = 'EL PAIS S.A.'
|
||||
category = 'news, politics, Uruguay'
|
||||
language = 'es'
|
||||
timefmt = '[%a, %d %b, %Y]'
|
||||
use_embedded_content = False
|
||||
recursion = 2
|
||||
encoding = 'iso-8859-1'
|
||||
masthead_url = 'http://www.elpais.com.uy/Images/09/cabezal/logo_PDEP.png'
|
||||
publication_type = 'newspaper'
|
||||
remove_javascript = True
|
||||
no_stylesheets = True
|
||||
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 100
|
||||
max_articles_per_feed = 200
|
||||
keep_only_tags = [
|
||||
dict(name='h1'),
|
||||
dict(name='div', attrs={'id':'Contenido'})
|
||||
]
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher' : publisher
|
||||
, 'language' : language
|
||||
}
|
||||
remove_tags = [
|
||||
dict(name='div', attrs={'class':['date_text', 'comments', 'form_section', 'share_it']}),
|
||||
dict(name='div', attrs={'id':['relatedPosts', 'spacer', 'banner_izquierda', 'right_container']}),
|
||||
@ -38,6 +49,8 @@ class General(BasicNewsRecipe):
|
||||
h3{font-size: 14px;color:#999999; font-family:Geneva, Arial, Helvetica, sans-serif;font-weight: bold;}
|
||||
h2{color:#666666; font-family:Geneva, Arial, Helvetica, sans-serif;font-size:small;}
|
||||
p {font-family:Arial,Helvetica,sans-serif;}
|
||||
body{font-family: Verdana,Arial,Helvetica,sans-serif }
|
||||
img{margin-bottom: 0.4em; display:block;}
|
||||
'''
|
||||
feeds = [
|
||||
(u'Ultimo Momento', u'http://www.elpais.com.uy/formatos/rss/index.asp?seccion=umomento'),
|
||||
@ -47,7 +60,7 @@ class General(BasicNewsRecipe):
|
||||
(u'Espectaculos', u'http://www.elpais.com.uy/formatos/rss/index.asp?seccion=espectaculos'),
|
||||
(u'Deportes', u'http://www.elpais.com.uy/formatos/rss/index.asp?seccion=deportes'),
|
||||
(u'Ciudades', u'http://www.elpais.com.uy/formatos/rss/index.asp?seccion=ciudades'),
|
||||
(u'Economia', u'http://www.elpais.com.uy/formatos/rss/index.asp?seccion=economia')
|
||||
(u'Economia', u'http://www.elpais.com.uy/formatos/rss/index.asp?seccion=economia')
|
||||
]
|
||||
|
||||
def get_cover_url(self):
|
||||
|
54
resources/recipes/la_rioja.recipe
Normal file
@ -0,0 +1,54 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
www.larioja.com
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class LaRioja(BasicNewsRecipe):
|
||||
title = 'La Rioja'
|
||||
__author__ = 'Arturo Martinez Nieves'
|
||||
description = 'Noticias de La Rioja y el resto del mundo'
|
||||
publisher = 'La Rioja'
|
||||
category = 'news, politics, Spain'
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 200
|
||||
no_stylesheets = True
|
||||
encoding = 'cp1252'
|
||||
use_embedded_content = False
|
||||
language = 'es'
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.larioja.com/includes/manuales/larioja/include-lariojapapeldigital-zonac-fondocabecera01.jpg'
|
||||
extra_css = ' body{font-family: Arial,Helvetica,sans-serif } img{margin-bottom: 0.4em} .photo-caption{font-size: x-small} '
|
||||
|
||||
conversion_options = {
|
||||
'comment' : description
|
||||
, 'tags' : category
|
||||
, 'publisher' : publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
keep_only_tags = [
|
||||
dict(attrs={'id':'title'})
|
||||
,dict(attrs={'class':['overhead','headline','subhead','date','text','noticia_cont','desarrollo']})
|
||||
]
|
||||
remove_tags = [dict(name='ul')]
|
||||
remove_attributes = ['width','height']
|
||||
|
||||
|
||||
feeds = [
|
||||
(u'Ultimas Noticias' , u'http://www.larioja.com/rss/feeds/ultima.xml' )
|
||||
,(u'Portada' , u'http://www.larioja.com/rss/feeds/portada.xml' )
|
||||
,(u'Mundo' , u'http://www.larioja.com/rss/feeds/mundo.xml' )
|
||||
,(u'Espana' , u'http://www.larioja.com/rss/feeds/espana.xml' )
|
||||
,(u'Region' , u'http://www.larioja.com/rss/feeds/region.xml' )
|
||||
,(u'Comarcas' , u'http://www.larioja.com/rss/feeds/comarcas.xml')
|
||||
,(u'Deportes' , u'http://www.larioja.com/rss/feeds/deportes.xml' )
|
||||
,(u'Economia' , u'http://www.larioja.com/rss/feeds/economia.xml' )
|
||||
,(u'Cultura' , u'http://www.larioja.com/rss/feeds/cultura.xml' )
|
||||
,(u'Opinion' , u'http://www.larioja.com/rss/feeds/opinion.xml' )
|
||||
,(u'Sociedad' , u'http://www.larioja.com/rss/feeds/sociedad.xml' )
|
||||
|
||||
]
|
||||
|
@ -20,11 +20,14 @@ class Lanacion(BasicNewsRecipe):
|
||||
publication_type = 'newspaper'
|
||||
remove_empty_feeds = True
|
||||
masthead_url = 'http://www.lanacion.com.ar/imgs/layout/logos/ln341x47.gif'
|
||||
extra_css = """ h1{font-family: Georgia,serif}
|
||||
extra_css = """ h1{font-family: Georgia,serif}
|
||||
h2{color: #626262}
|
||||
body{font-family: Arial,sans-serif}
|
||||
img{margin-top: 0.5em; margin-bottom: 0.2em}
|
||||
img{margin-top: 0.5em; margin-bottom: 0.2em; display: block}
|
||||
.notaFecha{color: #808080}
|
||||
.notaEpigrafe{font-size: x-small}
|
||||
.topNota h1{font-family: Arial,sans-serif} """
|
||||
.topNota h1{font-family: Arial,sans-serif}
|
||||
"""
|
||||
|
||||
|
||||
conversion_options = {
|
||||
@ -38,12 +41,12 @@ class Lanacion(BasicNewsRecipe):
|
||||
remove_tags = [
|
||||
dict(name='div' , attrs={'class':'notaComentario floatFix noprint' })
|
||||
,dict(name='ul' , attrs={'class':['cajaHerramientas cajaTop noprint','herramientas noprint']})
|
||||
,dict(name='div' , attrs={'class':'cajaHerramientas noprint' })
|
||||
,dict(attrs={'class':['titulosMultimedia','derecha','techo color','encuesta','izquierda compartir','floatFix']})
|
||||
,dict(name=['iframe','embed','object','form','base','hr'])
|
||||
,dict(name='div' , attrs={'class':['cajaHerramientas noprint','cajaHerramientas floatFix'] })
|
||||
,dict(attrs={'class':['titulosMultimedia','derecha','techo color','encuesta','izquierda compartir','floatFix','videoCentro']})
|
||||
,dict(name=['iframe','embed','object','form','base','hr','meta','link','input'])
|
||||
]
|
||||
remove_tags_after = dict(attrs={'class':['tags','nota-destacado']})
|
||||
remove_attributes = ['height','width','visible']
|
||||
remove_attributes = ['height','width','visible','onclick','data-count','name']
|
||||
|
||||
feeds = [
|
||||
(u'Ultimas noticias' , u'http://www.lanacion.com.ar/herramientas/rss/index.asp?origen=2' )
|
||||
|
22
resources/recipes/matichon.recipe
Normal file
@ -0,0 +1,22 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1290412756(BasicNewsRecipe):
|
||||
__author__ = 'Anat R.'
|
||||
title = u'Matichon'
|
||||
oldest_article = 7
|
||||
language = 'th'
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
use_embedded_content = False
|
||||
feeds = [(u'News', u'http://www.matichon.co.th/rss/news_article.xml'),
|
||||
(u'Columns', u'http://www.matichon.co.th/rss/news_columns.xml'),
|
||||
(u'Politics', u'http://www.matichon.co.th/rss/news_politic.xml'),
|
||||
(u'Business', u'http://www.matichon.co.th/rss/news_business.xml'),
|
||||
(u'World', u'http://www.matichon.co.th/rss/news_world.xml'),
|
||||
(u'Sports', u'http://www.matichon.co.th/rss/news_sport.xml'),
|
||||
(u'Entertainment', u'http://www.matichon.co.th/rss/news_entertainment.xml')]
|
||||
keep_only_tags = []
|
||||
keep_only_tags.append(dict(name = 'h3', attrs = {'class' : 'read-h'}))
|
||||
keep_only_tags.append(dict(name = 'p', attrs = {'class' : 'read-time'}))
|
||||
keep_only_tags.append(dict(name = 'div', attrs = {'class' : 'news-content'}))
|
11
resources/recipes/nacionred.recipe
Normal file
@ -0,0 +1,11 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class AdvancedUserRecipe1291022049(BasicNewsRecipe):
|
||||
title = u'NacionRed.com'
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
language = 'es'
|
||||
__author__ = 'Arturo Martinez Nieves'
|
||||
|
||||
feeds = [(u'NacionRed.com', u'http://feeds.weblogssl.com/nacionred?format=xml')]
|
||||
|
@ -32,15 +32,15 @@ class NewYorker(BasicNewsRecipe):
|
||||
, 'publisher' : publisher
|
||||
, 'language' : language
|
||||
}
|
||||
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='div', attrs={'class':'headers'})
|
||||
,dict(name='div', attrs={'id':['articleheads','items-container','articleRail','articletext','photocredits']})
|
||||
]
|
||||
remove_tags = [
|
||||
dict(name=['meta','iframe','base','link','embed','object'])
|
||||
,dict(attrs={'class':['utils','articleRailLinks','icons'] })
|
||||
,dict(attrs={'id':['show-header','show-footer'] })
|
||||
,dict(attrs={'class':['utils','articleRailLinks','icons'] })
|
||||
,dict(attrs={'id':['show-header','show-footer'] })
|
||||
]
|
||||
remove_attributes = ['lang']
|
||||
feeds = [(u'The New Yorker', u'http://feeds.newyorker.com/services/rss/feeds/everything.xml')]
|
||||
@ -58,4 +58,4 @@ class NewYorker(BasicNewsRecipe):
|
||||
if cover_item:
|
||||
cover_url = 'http://www.newyorker.com' + cover_item['src'].strip()
|
||||
return cover_url
|
||||
|
||||
|
||||
|
@ -13,6 +13,8 @@ class RevistaMuyInteresante(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
|
||||
conversion_options = {'linearize_tables': True}
|
||||
|
||||
extra_css = ' .txt_articulo{ font-family: sans-serif; font-size: medium; text-align: justify } .contentheading{font-family: serif; font-size: large; font-weight: bold; color: #000000; text-align: center}'
|
||||
|
||||
|
||||
@ -39,11 +41,12 @@ class RevistaMuyInteresante(BasicNewsRecipe):
|
||||
keep_only_tags = [dict(name='div', attrs={'class':['article']}),dict(name='td', attrs={'class':['txt_articulo']})]
|
||||
|
||||
remove_tags = [
|
||||
dict(name=['object','link','script','ul'])
|
||||
dict(name=['object','link','script','ul','iframe','ins'])
|
||||
,dict(name='div', attrs={'id':['comment']})
|
||||
,dict(name='td', attrs={'class':['buttonheading']})
|
||||
,dict(name='div', attrs={'class':['tags_articles']})
|
||||
,dict(name='div', attrs={'class':['tags_articles','bajo_title']})
|
||||
,dict(name='table', attrs={'class':['pagenav']})
|
||||
,dict(name='form', attrs={'class':['voteform']})
|
||||
]
|
||||
|
||||
remove_tags_after = dict(name='div', attrs={'class':'tags_articles'})
|
||||
@ -115,3 +118,5 @@ class RevistaMuyInteresante(BasicNewsRecipe):
|
||||
if link_item:
|
||||
cover_url = "http://www.muyinteresante.es"+link_item['src']
|
||||
return cover_url
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@ class RusiaHoy(BasicNewsRecipe):
|
||||
use_embedded_content = False
|
||||
language = 'es'
|
||||
remove_empty_feeds = True
|
||||
extra_css = """
|
||||
extra_css = """
|
||||
body{font-family: Arial,sans-serif }
|
||||
.article_article_title{font-size: xx-large; font-weight: bold}
|
||||
.article_date{color: black; font-size: small}
|
||||
@ -44,4 +44,4 @@ class RusiaHoy(BasicNewsRecipe):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
||||
|
||||
|
||||
|
59
resources/recipes/the_workingham_times.recipe
Normal file
@ -0,0 +1,59 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
www.getwokingham.co.uk
|
||||
'''
|
||||
|
||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
|
||||
class TheWokinghamTimes(BasicNewsRecipe):
|
||||
title = 'The Wokingham Times'
|
||||
__author__ = 'Darko Miletic'
|
||||
description = 'News from UK'
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
use_embedded_content = False
|
||||
encoding = 'utf8'
|
||||
publisher = 'The Wokingham Times - S&B media'
|
||||
category = 'news, UK, world'
|
||||
language = 'en_GB'
|
||||
publication_type = 'newsportal'
|
||||
extra_css = """
|
||||
body{ font-family: Arial,sans-serif }
|
||||
img{display: block; margin-bottom: 0.4em}
|
||||
"""
|
||||
|
||||
conversion_options = {
|
||||
'comments' : description
|
||||
,'tags' : category
|
||||
,'language' : language
|
||||
,'publisher' : publisher
|
||||
}
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'id':'article-body'})]
|
||||
remove_tags = [
|
||||
dict(name='div' , attrs={'class':['ad']})
|
||||
,dict(name=['meta','base','iframe','embed','object'])
|
||||
,dict(name='span' , attrs={'class':'caption small'})
|
||||
]
|
||||
remove_attributes = ['width','height','lang']
|
||||
|
||||
feeds = [
|
||||
('Home' , 'http://www.getwokingham.co.uk/rss.xml' )
|
||||
,('News' , 'http://www.getwokingham.co.uk/news/rss.xml' )
|
||||
,('Entertainment', 'http://www.getwokingham.co.uk/entertainment/rss.xml')
|
||||
,('Lifestyle' , 'http://www.getwokingham.co.uk/lifestyle/rss.xml' )
|
||||
]
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
for item in soup.findAll('a'):
|
||||
if item.string is not None:
|
||||
str = item.string
|
||||
item.replaceWith(str)
|
||||
else:
|
||||
item.name = 'span'
|
||||
del item['href']
|
||||
return soup
|
@ -8,7 +8,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
import re
|
||||
|
||||
class YOLNews(BasicNewsRecipe):
|
||||
title = u'YOMIURI ONLINE(Latest)'
|
||||
title = u'Yomiuri Online (Latest)'
|
||||
__author__ = 'Hiroshi Miura'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 50
|
||||
|
@ -8,7 +8,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
||||
import re
|
||||
|
||||
class YOLNews(BasicNewsRecipe):
|
||||
title = u'YOMIURI ONLINE(World)'
|
||||
title = u'Yomiuri Online (World)'
|
||||
__author__ = 'Hiroshi Miura'
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 50
|
||||
|
@ -2022,7 +2022,8 @@ var Hyphenator = (function (window) {
|
||||
if (n.nodeType === 3 && n.data.length >= min) { //type 3 = #text -> hyphenate!
|
||||
n.data = n.data.replace(Hyphenator.languages[lang].genRegExp, hyphenate);
|
||||
} else if (n.nodeType === 1) {
|
||||
if (n.lang !== '') {
|
||||
// Modified by Kovid to use element lang only if it has been loaded
|
||||
if (n.lang !== '' && Hyphenator.languages.hasOwnProperty(n.lang)) {
|
||||
Hyphenator.hyphenate(n, n.lang);
|
||||
} else {
|
||||
Hyphenator.hyphenate(n, lang);
|
||||
@ -2139,4 +2140,4 @@ if (Hyphenator.isBookmarklet()) {
|
||||
Hyphenator.config({displaytogglebox: true, intermediatestate: 'visible', doframes: true});
|
||||
Hyphenator.config(Hyphenator.getConfigFromURI());
|
||||
Hyphenator.run();
|
||||
}
|
||||
}
|
||||
|
@ -6,14 +6,43 @@
|
||||
|
||||
function scale_images() {
|
||||
$("img:visible").each(function() {
|
||||
var offset = $(this).offset();
|
||||
var img = $(this);
|
||||
var offset = img.offset();
|
||||
var avail_width = window.innerWidth - offset.left - 5;
|
||||
var avail_height = window.innerHeight - 5;
|
||||
img.css('width', img.data('orig-width'));
|
||||
img.css('height', img.data('orig-height'));
|
||||
var width = img.width();
|
||||
var height = img.height();
|
||||
var ratio = 0;
|
||||
|
||||
if (width > avail_width) {
|
||||
ratio = avail_width / width;
|
||||
img.css('width', avail_width+'px');
|
||||
img.css('height', (ratio*height) + 'px');
|
||||
height = height * ratio;
|
||||
width = width * ratio;
|
||||
}
|
||||
|
||||
if (height > avail_height) {
|
||||
ratio = avail_height / height;
|
||||
img.css('height', avail_height);
|
||||
img.css('width', width * ratio);
|
||||
}
|
||||
//window.py_bridge.debug(window.getComputedStyle(this, '').getPropertyValue('max-width'));
|
||||
$(this).css("max-width", (window.innerWidth-offset.left-5)+"px");
|
||||
$(this).css("max-height", (window.innerHeight-5)+"px");
|
||||
});
|
||||
}
|
||||
|
||||
function store_original_size_attributes() {
|
||||
$("img").each(function() {
|
||||
var img = $(this);
|
||||
img.data('orig-width', img.css('width'));
|
||||
img.data('orig-height', img.css('height'));
|
||||
});
|
||||
}
|
||||
|
||||
function setup_image_scaling_handlers() {
|
||||
store_original_size_attributes();
|
||||
scale_images();
|
||||
$(window).resize(function(){
|
||||
scale_images();
|
||||
|
@ -90,11 +90,13 @@ fc_lib = '/usr/lib'
|
||||
podofo_inc = '/usr/include/podofo'
|
||||
podofo_lib = '/usr/lib'
|
||||
chmlib_inc_dirs = chmlib_lib_dirs = []
|
||||
sqlite_inc_dirs = []
|
||||
|
||||
if iswindows:
|
||||
prefix = r'C:\cygwin\home\kovid\sw'
|
||||
sw_inc_dir = os.path.join(prefix, 'include')
|
||||
sw_lib_dir = os.path.join(prefix, 'lib')
|
||||
sqlite_inc_dirs = [sw_inc_dir]
|
||||
fc_inc = os.path.join(sw_inc_dir, 'fontconfig')
|
||||
fc_lib = sw_lib_dir
|
||||
chmlib_inc_dirs = consolidate('CHMLIB_INC_DIR', os.path.join(prefix,
|
||||
|
@ -18,7 +18,7 @@ __all__ = [
|
||||
'pypi_register', 'pypi_upload', 'upload_to_server',
|
||||
'upload_user_manual', 'upload_to_mobileread', 'upload_demo',
|
||||
'upload_to_sourceforge', 'upload_to_google_code',
|
||||
'linux32', 'linux64', 'linux', 'linux_freeze', 'linux_freeze2',
|
||||
'linux32', 'linux64', 'linux', 'linux_freeze',
|
||||
'osx32_freeze', 'osx', 'rsync', 'push',
|
||||
'win32_freeze', 'win32', 'win',
|
||||
'stage1', 'stage2', 'stage3', 'stage4', 'publish'
|
||||
@ -79,10 +79,8 @@ from setup.installer.linux import Linux, Linux32, Linux64
|
||||
linux = Linux()
|
||||
linux32 = Linux32()
|
||||
linux64 = Linux64()
|
||||
from setup.installer.linux.freeze import LinuxFreeze
|
||||
from setup.installer.linux.freeze2 import LinuxFreeze
|
||||
linux_freeze = LinuxFreeze()
|
||||
from setup.installer.linux.freeze2 import LinuxFreeze2
|
||||
linux_freeze2 = LinuxFreeze2()
|
||||
|
||||
from setup.installer.osx import OSX
|
||||
osx = OSX()
|
||||
|
@ -18,7 +18,7 @@ from setup.build_environment import fc_inc, fc_lib, chmlib_inc_dirs, \
|
||||
QMAKE, msvc, MT, win_inc, win_lib, png_inc_dirs, win_ddk, \
|
||||
magick_inc_dirs, magick_lib_dirs, png_lib_dirs, png_libs, \
|
||||
magick_error, magick_libs, ft_lib_dirs, ft_libs, jpg_libs, \
|
||||
jpg_lib_dirs, chmlib_lib_dirs
|
||||
jpg_lib_dirs, chmlib_lib_dirs, sqlite_inc_dirs
|
||||
MT
|
||||
isunix = islinux or isosx or isfreebsd
|
||||
|
||||
@ -58,6 +58,11 @@ if iswindows:
|
||||
|
||||
extensions = [
|
||||
|
||||
Extension('sqlite_custom',
|
||||
['calibre/library/sqlite_custom.c'],
|
||||
inc_dirs=sqlite_inc_dirs
|
||||
),
|
||||
|
||||
Extension('chmlib',
|
||||
['calibre/utils/chm/swig_chm.c'],
|
||||
libraries=['ChmLib' if iswindows else 'chm'],
|
||||
|
@ -1,244 +0,0 @@
|
||||
Changes from 4.0 to 4.0.1
|
||||
1) Added support for Python 2.6. On Windows a manifest file is now required
|
||||
because of the switch to using the new Microsoft C runtime.
|
||||
2) Ensure that hooks are run for builtin modules.
|
||||
|
||||
Changes from 4.0b1 to 4.0
|
||||
1) Added support for copying files to the target directory.
|
||||
2) Added support for a hook that runs when a module is missing.
|
||||
3) Added support for binary path includes as well as excludes; use sequences
|
||||
rather than dictionaries as a more convenient API; exclude the standard
|
||||
locations for 32-bit and 64-bit libaries in multi-architecture systems.
|
||||
4) Added support for searching zip files (egg files) for modules.
|
||||
5) Added support for handling system exit exceptions similarly to what Python
|
||||
does itself as requested by Sylvain.
|
||||
6) Added code to wait for threads to shut down like the normal Python
|
||||
interpreter does. Thanks to Mariano Disanzo for discovering this
|
||||
discrepancy.
|
||||
7) Hooks added or modified based on feedback from many people.
|
||||
8) Don't include the version name in the display name of the MSI.
|
||||
9) Use the OS dependent path normalization routines rather than simply use the
|
||||
lowercase value as on Unix case is important; thanks to Artie Eoff for
|
||||
pointing this out.
|
||||
10) Include a version attribute in the cx_Freeze package and display it in the
|
||||
output for the --version option to the script.
|
||||
11) Include build instructions as requested by Norbert Sebok.
|
||||
12) Add support for copying files when modules are included which require data
|
||||
files to operate properly; add support for copying the necessary files for
|
||||
the Tkinter and matplotlib modules.
|
||||
13) Handle deferred imports recursively as needed; ensure that from lists do
|
||||
not automatically indicate that they are part of the module or the deferred
|
||||
import processing doesn't actually work!
|
||||
14) Handle the situation where a module imports everything from a package and
|
||||
the __all__ variable has been defined but the package has not actually
|
||||
imported everything in the __all__ variable during initialization.
|
||||
15) Modified license text to more closely match the Python Software Foundation
|
||||
license as was intended.
|
||||
16) Added sample script for freezing an application using matplotlib.
|
||||
17) Renamed freeze to cxfreeze to avoid conflict with another package that uses
|
||||
that executable as requested by Siegfried Gevatter.
|
||||
|
||||
Changes from 3.0.3 to 4.0b1
|
||||
1) Added support for placing modules in library.zip or in a separate zip file
|
||||
for each executable that is produced.
|
||||
2) Added support for copying binary dependent files (DLLs and shared
|
||||
libraries)
|
||||
3) Added support for including all submodules in a package
|
||||
4) Added support for including icons in Windows executables
|
||||
5) Added support for constants module which can be used for determining
|
||||
certain build constants at runtime
|
||||
6) Added support for relative imports available in Python 2.5 and up
|
||||
7) Added support for building Windows installers (Python 2.5 and up) and
|
||||
RPM packages
|
||||
8) Added support for distutils configuration scripts
|
||||
9) Added support for hooks which can force inclusion or exclusion of modules
|
||||
when certain modules are included
|
||||
10) Added documentation and samples
|
||||
11) Added setup.py for building the cx_Freeze package instead of a script
|
||||
used to build only the frozen bases
|
||||
12) FreezePython renamed to a script called freeze in the Python distribution
|
||||
13) On Linux and other platforms that support it set LD_RUN_PATH to include
|
||||
the directory in which the executable is located
|
||||
|
||||
Changes from 3.0.2 to 3.0.3
|
||||
1) In Common.c, used MAXPATHLEN defined in the Python OS independent include
|
||||
file rather than the PATH_MAX define which is OS dependent and is not
|
||||
available on IRIX as noted by Andrew Jones.
|
||||
2) In the initscript ConsoleSetLibPath.py, added lines from initscript
|
||||
Console.py that should have been there since the only difference between
|
||||
that script and this one is the automatic re-execution of the executable.
|
||||
3) Added an explicit "import encodings" to the initscripts in order to handle
|
||||
Unicode encodings a little better. Thanks to Ralf Schmitt for pointing out
|
||||
the problem and its solution.
|
||||
4) Generated a meaningful name for the extension loader script so that it is
|
||||
clear which particular extension module is being loaded when an exception
|
||||
is being raised.
|
||||
5) In MakeFrozenBases.py, use distutils to figure out a few more
|
||||
platform-dependent linker flags as suggested by Ralf Schmitt.
|
||||
|
||||
Changes from 3.0.1 to 3.0.2
|
||||
1) Add support for compressing the byte code in the zip files that are
|
||||
produced.
|
||||
2) Add better support for the win32com package as requested by Barry Scott.
|
||||
3) Prevent deletion of target file if it happens to be identical to the
|
||||
source file.
|
||||
4) Include additional flags for local modifications to a Python build as
|
||||
suggested by Benjamin Rutt.
|
||||
5) Expanded instructions for building cx_Freeze from source based on a
|
||||
suggestion from Gregg Lind.
|
||||
6) Fix typo in help string.
|
||||
|
||||
Changes from 3.0 to 3.0.1
|
||||
1) Added option --default-path which is used to specify the path used when
|
||||
finding modules. This is particularly useful when performing cross
|
||||
compilations (such as for building a frozen executable for Windows CE).
|
||||
2) Added option --shared-lib-name which can be used to specify the name of
|
||||
the shared library (DLL) implementing the Python runtime that is required
|
||||
for the frozen executable to work. This option is also particularly useful
|
||||
when cross compiling since the normal method for determining this
|
||||
information cannot be used.
|
||||
3) Added option --zip-include which allows for additional files to be added
|
||||
to the zip file that contains the modules that implement the Python
|
||||
script. Thanks to Barray Warsaw for providing the initial patch.
|
||||
4) Added support for handling read-only files properly. Thanks to Peter
|
||||
Grayson for pointing out the problem and providing a solution.
|
||||
5) Added support for a frozen executable to be a symbolic link. Thanks to
|
||||
Robert Kiendl for providing the initial patch.
|
||||
6) Enhanced the support for running a frozen executable that uses an existing
|
||||
Python installation to locate modules it requires. This is primarily of
|
||||
use for embedding Python where the interface is C but the ability to run
|
||||
from source is still desired.
|
||||
7) Modified the documentation to indicate that building from source on
|
||||
Windows currently requires the mingw compiler (http://www.mingw.org).
|
||||
8) Workaround the problem in Python 2.3 (fixed in Python 2.4) which causes a
|
||||
broken module to be left in sys.modules if an ImportError takes place
|
||||
during the execution of the code in that module. Thanks to Roger Binns
|
||||
for pointing this out.
|
||||
|
||||
Changes from 3.0 beta3 to 3.0
|
||||
1) Ensure that ldd is only run on extension modules.
|
||||
2) Allow for using a compiler other than gcc for building the frozen base
|
||||
executables by setting the environment variable CC.
|
||||
3) Ensure that the import lock is not held while executing the main script;
|
||||
otherwise, attempts to import a module within a thread will hang that
|
||||
thread as noted by Roger Binns.
|
||||
4) Added support for replacing the paths in all frozen modules with something
|
||||
else (so that for example the path of the machine on which the freezing
|
||||
was done is not displayed in tracebacks)
|
||||
|
||||
Changes from 3.0 beta2 to 3.0 beta3
|
||||
1) Explicitly include the warnings module so that at runtime warnings are
|
||||
suppressed as when running Python normally.
|
||||
2) Improve the extension loader so that an ImportError is raised when the
|
||||
dynamic module is not located; otherwise an error about missing attributes
|
||||
is raised instead.
|
||||
3) Extension loaders are only created when copying dependencies since the
|
||||
normal module should be loadable in the situation where a Python
|
||||
installation is available.
|
||||
4) Added support for Python 2.4.
|
||||
5) Fixed the dependency checking for wxPython to be a little more
|
||||
intelligent.
|
||||
|
||||
Changes from 3.0 beta1 to 3.0 beta2
|
||||
1) Fix issues with locating the initscripts and bases relative to the
|
||||
directory in which the executable was started.
|
||||
2) Added new base executable ConsoleKeepPath which is used when an existing
|
||||
Python installation is required (such as for FreezePython itself).
|
||||
3) Forced the existence of a Python installation to be ignored when using the
|
||||
standard Console base executable.
|
||||
4) Remove the existing file when copying dependent files; otherwise, an error
|
||||
is raised when attempting to overwrite read-only files.
|
||||
5) Added option -O (or -OO) to FreezePython to set the optimization used when
|
||||
generating bytecode.
|
||||
|
||||
Changes from 2.2 to 3.0 beta1
|
||||
1) cx_Freeze now requires Python 2.3 or higher since it takes advantage of
|
||||
the ability of Python 2.3 and higher to import modules from zip files.
|
||||
This makes the freezing process considerably simpler and also allows for
|
||||
the execution of multiple frozen packages (such as found in COM servers or
|
||||
shared libraries) without requiring modification to the Python modules.
|
||||
2) All external dependencies have been removed. cx_Freeze now only requires
|
||||
a standard Python distribution to do its work.
|
||||
3) Added the ability to define the initialization scripts that cx_Freeze uses
|
||||
on startup of the frozen program. Previously, these scripts were written
|
||||
in C and could not easily be changed; now they are written in Python and
|
||||
can be found in the initscripts directory (and chosen with the
|
||||
new --init-script option to FreezePython).
|
||||
4) The base executable ConsoleSetLibPath has been removed and replaced with
|
||||
the initscript ConsoleSetLibPath.
|
||||
5) Removed base executables for Win32 services and Win32 COM servers. This
|
||||
functionality will be restored in the future but it is not currently in a
|
||||
state that is ready for release. If this functionality is required, please
|
||||
use py2exe or contact me for my work in progress.
|
||||
6) The attribute sys.frozen is now set so that more recent pywin32 modules
|
||||
work as expected when frozen.
|
||||
7) Added option --include-path to FreezePython to allow overriding of
|
||||
sys.path without modifying the environment variable PYTHONPATH.
|
||||
8) Added option --target-dir/--install-dir to specify the directory in which
|
||||
the frozen executable and its dependencies will be placed.
|
||||
9) Removed the option --shared-lib since it was used for building shared
|
||||
libraries and can be managed with the initscript SharedLib.py.
|
||||
10) MakeFrozenBases.py now checks the platform specific include directory as
|
||||
requested by Michael Partridge.
|
||||
|
||||
|
||||
Changes from 2.1 to 2.2
|
||||
1) Add option (--ext-list-file) to FreezePython to write the list of
|
||||
extensions copied to the installation directory to a file. This option is
|
||||
useful in cases where multiple builds are performed into the same
|
||||
installation directory.
|
||||
2) Pass the arguments on the command line through to Win32 GUI applications.
|
||||
Thanks to Michael Porter for pointing this out.
|
||||
3) Link directly against the python DLL when building the frozen bases on
|
||||
Windows, thus eliminating the need for building an import library.
|
||||
4) Force sys.path to include the directory in which the script to be frozen
|
||||
is found.
|
||||
5) Make sure that the installation directory exists before attempting to
|
||||
copy the target binary into it.
|
||||
6) The Win32GUI base has been modified to display fatal errors in message
|
||||
boxes, rather than printing errors to stderr, since on Windows the
|
||||
standard file IO handles are all closed.
|
||||
|
||||
Changes from 2.0 to 2.1
|
||||
1) Remove dependency on Python 2.2. Thanks to Paul Moore for not only
|
||||
pointing it out but providing patches.
|
||||
2) Set up the list of frozen modules in advance, rather than doing it after
|
||||
Python is initialized so that implicit imports done by Python can be
|
||||
satisfied. The bug in Python 2.3 that demonstrated this issue has been
|
||||
fixed in the first release candidate. Thanks to Thomas Heller for pointing
|
||||
out the obvious in this instance!
|
||||
3) Added additional base executable (ConsoleSetLibPath) to support setting
|
||||
the LD_LIBRARY_PATH variable on Unix platforms and restarting the
|
||||
executable to put the new setting into effect. This is primarily of use
|
||||
in distributing wxPython applications on Unix where the shared library
|
||||
has an embedded RPATH value which can cause problems.
|
||||
4) Small improvements of documentation based on feedback from several people.
|
||||
5) Print information about the files written or copied during the freezing
|
||||
process.
|
||||
6) Do not copy extensions when freezing if the path is being overridden since
|
||||
it is expected that a full Python installation is available to the target
|
||||
users of the frozen binary.
|
||||
7) Provide meaningful error message when the wxPython library cannot be
|
||||
found during the freezing process.
|
||||
|
||||
Changes from 1.1 to 2.0
|
||||
1) Added support for in process (DLL) COM servers using PythonCOM.
|
||||
2) Ensured that the frozen flag is set prior to determining the full path for
|
||||
the program in order to avoid warnings about Python not being found on
|
||||
some platforms.
|
||||
3) Added include file and resource file to the source tree to avoid the
|
||||
dependency on the Wine message compiler for Win32 builds.
|
||||
4) Dropped the option --copy-extensions; this now happens automatically since
|
||||
the resulting binary is useless without them.
|
||||
5) Added a sample for building a Win32 service.
|
||||
6) Make use of improved modules from Python 2.3 (which function under 2.2)
|
||||
|
||||
Changes from 1.0 to 1.1
|
||||
1) Fixed import error with C extensions in packages; thanks to Thomas Heller
|
||||
for pointing out the solution to this problem.
|
||||
2) Added options to FreezePython to allow for the inclusion of modules which
|
||||
will not be found by the module finder (--include-modules) and the
|
||||
exclusion of modules which will be found by the module finder but should
|
||||
not be included (--exclude-modules).
|
||||
3) Fixed typo in README.txt.
|
||||
|
@ -1,53 +0,0 @@
|
||||
Copyright © 2007-2008, Colt Engineering, Edmonton, Alberta, Canada.
|
||||
Copyright © 2001-2006, Computronix (Canada) Ltd., Edmonton, Alberta, Canada.
|
||||
All rights reserved.
|
||||
|
||||
NOTE: this license is derived from the Python Software Foundation License
|
||||
which can be found at http://www.python.org/psf/license
|
||||
|
||||
License for cx_Freeze 4.0.1
|
||||
---------------------------
|
||||
|
||||
1. This LICENSE AGREEMENT is between the copyright holders and the Individual
|
||||
or Organization ("Licensee") accessing and otherwise using cx_Freeze
|
||||
software in source or binary form and its associated documentation.
|
||||
|
||||
2. Subject to the terms and conditions of this License Agreement, the
|
||||
copyright holders hereby grant Licensee a nonexclusive, royalty-free,
|
||||
world-wide license to reproduce, analyze, test, perform and/or display
|
||||
publicly, prepare derivative works, distribute, and otherwise use cx_Freeze
|
||||
alone or in any derivative version, provided, however, that this License
|
||||
Agreement and this notice of copyright are retained in cx_Freeze alone or in
|
||||
any derivative version prepared by Licensee.
|
||||
|
||||
3. In the event Licensee prepares a derivative work that is based on or
|
||||
incorporates cx_Freeze or any part thereof, and wants to make the derivative
|
||||
work available to others as provided herein, then Licensee hereby agrees to
|
||||
include in any such work a brief summary of the changes made to cx_Freeze.
|
||||
|
||||
4. The copyright holders are making cx_Freeze available to Licensee on an
|
||||
"AS IS" basis. THE COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES,
|
||||
EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, THE COPYRIGHT
|
||||
HOLDERS MAKE NO AND DISCLAIM ANY REPRESENTATION OR WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF
|
||||
CX_FREEZE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
|
||||
|
||||
5. THE COPYRIGHT HOLDERS SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF
|
||||
CX_FREEZE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
|
||||
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING CX_FREEZE, OR ANY
|
||||
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
|
||||
|
||||
6. This License Agreement will automatically terminate upon a material breach
|
||||
of its terms and conditions.
|
||||
|
||||
7. Nothing in this License Agreement shall be deemed to create any relationship
|
||||
of agency, partnership, or joint venture between the copyright holders and
|
||||
Licensee. This License Agreement does not grant permission to use
|
||||
copyright holder's trademarks or trade name in a trademark sense to endorse
|
||||
or promote products or services of Licensee, or any third party.
|
||||
|
||||
8. By copying, installing or otherwise using cx_Freeze, Licensee agrees to be
|
||||
bound by the terms and conditions of this License Agreement.
|
||||
|
||||
Computronix® is a registered trademark of Computronix (Canada) Ltd.
|
||||
|
@ -1,6 +0,0 @@
|
||||
include MANIFEST.in
|
||||
include *.txt
|
||||
recursive-include doc *.html
|
||||
recursive-include initscripts *.py
|
||||
recursive-include samples *.py
|
||||
recursive-include source *.c *.rc
|
@ -1,22 +0,0 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: cx_Freeze
|
||||
Version: 4.0.1
|
||||
Summary: create standalone executables from Python scripts
|
||||
Home-page: http://cx-freeze.sourceforge.net
|
||||
Author: Anthony Tuininga
|
||||
Author-email: anthony.tuininga@gmail.com
|
||||
License: Python Software Foundation License
|
||||
Description: create standalone executables from Python scripts
|
||||
Keywords: freeze
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: Python Software Foundation License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: C
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Topic :: Software Development :: Build Tools
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Classifier: Topic :: System :: Software Distribution
|
||||
Classifier: Topic :: Utilities
|
@ -1,12 +0,0 @@
|
||||
Please see cx_Freeze.html for documentation on how to use cx_Freeze.
|
||||
|
||||
To build:
|
||||
|
||||
python setup.py build
|
||||
python setup.py install
|
||||
|
||||
On Windows I have used the MinGW compiler (http://www.mingw.org)
|
||||
|
||||
python setup.py build --compiler=mingw32
|
||||
python setup.py build --compiler=mingw32 install
|
||||
|
@ -1,14 +0,0 @@
|
||||
version = "4.0.1"
|
||||
|
||||
import sys
|
||||
from dist import *
|
||||
if sys.platform == "win32" and sys.version_info[:2] >= (2, 5):
|
||||
from windist import *
|
||||
from finder import *
|
||||
from freezer import *
|
||||
from main import *
|
||||
|
||||
del dist
|
||||
del finder
|
||||
del freezer
|
||||
|
@ -1,279 +0,0 @@
|
||||
import distutils.command.bdist_rpm
|
||||
import distutils.command.build
|
||||
import distutils.command.install
|
||||
import distutils.core
|
||||
import distutils.dir_util
|
||||
import distutils.dist
|
||||
import distutils.util
|
||||
import distutils.version
|
||||
import os
|
||||
import sys
|
||||
|
||||
import cx_Freeze
|
||||
|
||||
__all__ = [ "bdist_rpm", "build", "build_exe", "install", "install_exe",
|
||||
"setup" ]
|
||||
|
||||
class Distribution(distutils.dist.Distribution):
|
||||
|
||||
def __init__(self, attrs):
|
||||
self.executables = []
|
||||
distutils.dist.Distribution.__init__(self, attrs)
|
||||
|
||||
|
||||
class bdist_rpm(distutils.command.bdist_rpm.bdist_rpm):
|
||||
|
||||
def finalize_options(self):
|
||||
distutils.command.bdist_rpm.bdist_rpm.finalize_options(self)
|
||||
self.use_rpm_opt_flags = 1
|
||||
|
||||
def _make_spec_file(self):
|
||||
contents = distutils.command.bdist_rpm.bdist_rpm._make_spec_file(self)
|
||||
return [c for c in contents if c != 'BuildArch: noarch']
|
||||
|
||||
|
||||
class build(distutils.command.build.build):
|
||||
user_options = distutils.command.build.build.user_options + [
|
||||
('build-exe=', None, 'build directory for executables')
|
||||
]
|
||||
|
||||
def get_sub_commands(self):
|
||||
subCommands = distutils.command.build.build.get_sub_commands(self)
|
||||
if self.distribution.executables:
|
||||
subCommands.append("build_exe")
|
||||
return subCommands
|
||||
|
||||
def initialize_options(self):
|
||||
distutils.command.build.build.initialize_options(self)
|
||||
self.build_exe = None
|
||||
|
||||
def finalize_options(self):
|
||||
distutils.command.build.build.finalize_options(self)
|
||||
if self.build_exe is None:
|
||||
dirName = "exe.%s-%s" % \
|
||||
(distutils.util.get_platform(), sys.version[0:3])
|
||||
self.build_exe = os.path.join(self.build_base, dirName)
|
||||
|
||||
|
||||
class build_exe(distutils.core.Command):
|
||||
description = "build executables from Python scripts"
|
||||
user_options = [
|
||||
('build-exe=', 'b',
|
||||
'directory for built executables'),
|
||||
('optimize=', 'O',
|
||||
'optimization level: -O1 for "python -O", '
|
||||
'-O2 for "python -OO" and -O0 to disable [default: -O0]'),
|
||||
('excludes=', 'e',
|
||||
'comma-separated list of modules to exclude'),
|
||||
('includes=', 'i',
|
||||
'comma-separated list of modules to include'),
|
||||
('packages=', 'p',
|
||||
'comma-separated list of packages to include'),
|
||||
('replace-paths=', None,
|
||||
'comma-separated list of paths to replace in included modules'),
|
||||
('path=', None,
|
||||
'comma-separated list of paths to search'),
|
||||
('init-script=', 'i',
|
||||
'name of script to use during initialization'),
|
||||
('base=', None,
|
||||
'name of base executable to use'),
|
||||
('compressed', 'c',
|
||||
'create a compressed zipfile'),
|
||||
('copy-dependent-files', None,
|
||||
'copy all dependent files'),
|
||||
('create-shared-zip', None,
|
||||
'create a shared zip file containing shared modules'),
|
||||
('append-script-to-exe', None,
|
||||
'append the script module to the exe'),
|
||||
('include-in-shared-zip', None,
|
||||
'include the script module in the shared zip file'),
|
||||
('icon', None,
|
||||
'include the icon along with the frozen executable(s)'),
|
||||
('constants=', None,
|
||||
'comma-separated list of constants to include'),
|
||||
('include-files=', 'f',
|
||||
'list of tuples of additional files to include in distribution'),
|
||||
('bin-includes', None,
|
||||
'list of names of files to include when determining dependencies'),
|
||||
('bin-excludes', None,
|
||||
'list of names of files to exclude when determining dependencies')
|
||||
]
|
||||
boolean_options = ["compressed", "copy_dependent_files",
|
||||
"create_shared_zip", "append_script_to_exe",
|
||||
"include_in_shared_zip"]
|
||||
|
||||
def _normalize(self, attrName):
|
||||
value = getattr(self, attrName)
|
||||
if value is None:
|
||||
normalizedValue = []
|
||||
elif isinstance(value, basestring):
|
||||
normalizedValue = value.split()
|
||||
else:
|
||||
normalizedValue = list(value)
|
||||
setattr(self, attrName, normalizedValue)
|
||||
|
||||
def initialize_options(self):
|
||||
self.optimize = 0
|
||||
self.build_exe = None
|
||||
self.excludes = []
|
||||
self.includes = []
|
||||
self.packages = []
|
||||
self.replace_paths = []
|
||||
self.compressed = None
|
||||
self.copy_dependent_files = None
|
||||
self.init_script = None
|
||||
self.base = None
|
||||
self.path = None
|
||||
self.create_shared_zip = None
|
||||
self.append_script_to_exe = None
|
||||
self.include_in_shared_zip = None
|
||||
self.icon = None
|
||||
self.constants = []
|
||||
self.include_files = []
|
||||
self.bin_excludes = []
|
||||
self.bin_includes = []
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('build', ('build_exe', 'build_exe'))
|
||||
self.optimize = int(self.optimize)
|
||||
self._normalize("excludes")
|
||||
self._normalize("includes")
|
||||
self._normalize("packages")
|
||||
self._normalize("constants")
|
||||
|
||||
def run(self):
|
||||
metadata = self.distribution.metadata
|
||||
constantsModule = cx_Freeze.ConstantsModule(metadata.version)
|
||||
for constant in self.constants:
|
||||
parts = constant.split("=")
|
||||
if len(parts) == 1:
|
||||
name = constant
|
||||
value = None
|
||||
else:
|
||||
name, stringValue = parts
|
||||
value = eval(stringValue)
|
||||
constantsModule.values[name] = value
|
||||
freezer = cx_Freeze.Freezer(self.distribution.executables,
|
||||
[constantsModule], self.includes, self.excludes, self.packages,
|
||||
self.replace_paths, self.compressed, self.optimize,
|
||||
self.copy_dependent_files, self.init_script, self.base,
|
||||
self.path, self.create_shared_zip, self.append_script_to_exe,
|
||||
self.include_in_shared_zip, self.build_exe, icon = self.icon,
|
||||
includeFiles = self.include_files,
|
||||
binIncludes = self.bin_includes,
|
||||
binExcludes = self.bin_excludes)
|
||||
freezer.Freeze()
|
||||
|
||||
|
||||
class install(distutils.command.install.install):
|
||||
user_options = distutils.command.install.install.user_options + [
|
||||
('install-exe=', None,
|
||||
'installation directory for executables')
|
||||
]
|
||||
|
||||
def expand_dirs(self):
|
||||
distutils.command.install.install.expand_dirs(self)
|
||||
self._expand_attrs(['install_exe'])
|
||||
|
||||
def get_sub_commands(self):
|
||||
subCommands = distutils.command.install.install.get_sub_commands(self)
|
||||
if self.distribution.executables:
|
||||
subCommands.append("install_exe")
|
||||
return [s for s in subCommands if s != "install_egg_info"]
|
||||
|
||||
def initialize_options(self):
|
||||
distutils.command.install.install.initialize_options(self)
|
||||
self.install_exe = None
|
||||
|
||||
def finalize_options(self):
|
||||
if self.prefix is None and sys.platform == "win32":
|
||||
import _winreg
|
||||
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
|
||||
r"Software\Microsoft\Windows\CurrentVersion")
|
||||
prefix = str(_winreg.QueryValueEx(key, "ProgramFilesDir")[0])
|
||||
metadata = self.distribution.metadata
|
||||
dirName = "%s-%s" % (metadata.name, metadata.version)
|
||||
self.prefix = "%s/%s" % (prefix, dirName)
|
||||
distutils.command.install.install.finalize_options(self)
|
||||
self.convert_paths('exe')
|
||||
if self.root is not None:
|
||||
self.change_roots('exe')
|
||||
|
||||
def select_scheme(self, name):
|
||||
distutils.command.install.install.select_scheme(self, name)
|
||||
if self.install_exe is None:
|
||||
if sys.platform == "win32":
|
||||
self.install_exe = '$base'
|
||||
else:
|
||||
metadata = self.distribution.metadata
|
||||
dirName = "%s-%s" % (metadata.name, metadata.version)
|
||||
self.install_exe = '$base/lib/%s' % dirName
|
||||
|
||||
|
||||
class install_exe(distutils.core.Command):
|
||||
description = "install executables built from Python scripts"
|
||||
user_options = [
|
||||
('install-dir=', 'd', 'directory to install executables to'),
|
||||
('build-dir=', 'b', 'build directory (where to install from)'),
|
||||
('force', 'f', 'force installation (overwrite existing files)'),
|
||||
('skip-build', None, 'skip the build steps')
|
||||
]
|
||||
|
||||
def initialize_options(self):
|
||||
self.install_dir = None
|
||||
self.force = 0
|
||||
self.build_dir = None
|
||||
self.skip_build = None
|
||||
|
||||
def finalize_options(self):
|
||||
self.set_undefined_options('build', ('build_exe', 'build_dir'))
|
||||
self.set_undefined_options('install',
|
||||
('install_exe', 'install_dir'),
|
||||
('force', 'force'),
|
||||
('skip_build', 'skip_build'))
|
||||
|
||||
def run(self):
|
||||
if not self.skip_build:
|
||||
self.run_command('build_exe')
|
||||
self.outfiles = self.copy_tree(self.build_dir, self.install_dir)
|
||||
if sys.platform != "win32":
|
||||
baseDir = os.path.dirname(os.path.dirname(self.install_dir))
|
||||
binDir = os.path.join(baseDir, "bin")
|
||||
if not os.path.exists(binDir):
|
||||
os.makedirs(binDir)
|
||||
sourceDir = os.path.join("..", self.install_dir[len(baseDir) + 1:])
|
||||
for executable in self.distribution.executables:
|
||||
name = os.path.basename(executable.targetName)
|
||||
source = os.path.join(sourceDir, name)
|
||||
target = os.path.join(binDir, name)
|
||||
if os.path.exists(target):
|
||||
os.unlink(target)
|
||||
os.symlink(source, target)
|
||||
self.outfiles.append(target)
|
||||
|
||||
def get_inputs(self):
|
||||
return self.distribution.executables or []
|
||||
|
||||
def get_outputs(self):
|
||||
return self.outfiles or []
|
||||
|
||||
|
||||
def _AddCommandClass(commandClasses, name, cls):
|
||||
if name not in commandClasses:
|
||||
commandClasses[name] = cls
|
||||
|
||||
|
||||
def setup(**attrs):
|
||||
attrs["distclass"] = Distribution
|
||||
commandClasses = attrs.setdefault("cmdclass", {})
|
||||
if sys.platform == "win32":
|
||||
if sys.version_info[:2] >= (2, 5):
|
||||
_AddCommandClass(commandClasses, "bdist_msi", cx_Freeze.bdist_msi)
|
||||
else:
|
||||
_AddCommandClass(commandClasses, "bdist_rpm", cx_Freeze.bdist_rpm)
|
||||
_AddCommandClass(commandClasses, "build", build)
|
||||
_AddCommandClass(commandClasses, "build_exe", build_exe)
|
||||
_AddCommandClass(commandClasses, "install", install)
|
||||
_AddCommandClass(commandClasses, "install_exe", install_exe)
|
||||
distutils.core.setup(**attrs)
|
||||
|
@ -1,455 +0,0 @@
|
||||
"""
|
||||
Base class for finding modules.
|
||||
"""
|
||||
|
||||
import dis
|
||||
import imp
|
||||
import marshal
|
||||
import new
|
||||
import opcode
|
||||
import os
|
||||
import sys
|
||||
import zipfile
|
||||
|
||||
import cx_Freeze.hooks
|
||||
|
||||
BUILD_LIST = opcode.opmap["BUILD_LIST"]
|
||||
INPLACE_ADD = opcode.opmap["INPLACE_ADD"]
|
||||
LOAD_CONST = opcode.opmap["LOAD_CONST"]
|
||||
IMPORT_NAME = opcode.opmap["IMPORT_NAME"]
|
||||
IMPORT_FROM = opcode.opmap["IMPORT_FROM"]
|
||||
STORE_NAME = opcode.opmap["STORE_NAME"]
|
||||
STORE_GLOBAL = opcode.opmap["STORE_GLOBAL"]
|
||||
STORE_OPS = (STORE_NAME, STORE_GLOBAL)
|
||||
|
||||
__all__ = [ "Module", "ModuleFinder" ]
|
||||
|
||||
class ModuleFinder(object):
|
||||
|
||||
def __init__(self, includeFiles, excludes, path, replacePaths):
|
||||
self.includeFiles = includeFiles
|
||||
self.excludes = dict.fromkeys(excludes)
|
||||
self.replacePaths = replacePaths
|
||||
self.path = path or sys.path
|
||||
self.modules = []
|
||||
self.aliases = {}
|
||||
self._modules = dict.fromkeys(excludes)
|
||||
self._builtinModules = dict.fromkeys(sys.builtin_module_names)
|
||||
self._badModules = {}
|
||||
self._zipFileEntries = {}
|
||||
self._zipFiles = {}
|
||||
cx_Freeze.hooks.initialize(self)
|
||||
|
||||
def _AddModule(self, name):
|
||||
"""Add a module to the list of modules but if one is already found,
|
||||
then return it instead; this is done so that packages can be
|
||||
handled properly."""
|
||||
module = self._modules.get(name)
|
||||
if module is None:
|
||||
module = self._modules[name] = Module(name)
|
||||
self.modules.append(module)
|
||||
if name in self._badModules:
|
||||
del self._badModules[name]
|
||||
return module
|
||||
|
||||
def _DetermineParent(self, caller):
|
||||
"""Determine the parent to use when searching packages."""
|
||||
if caller is not None:
|
||||
if caller.path is not None:
|
||||
return caller
|
||||
return self._GetParentByName(caller.name)
|
||||
|
||||
def _EnsureFromList(self, caller, packageModule, fromList,
|
||||
deferredImports):
|
||||
"""Ensure that the from list is satisfied. This is only necessary for
|
||||
package modules. If the caller is the package itself, actually
|
||||
attempt to import right then since it must be a submodule; otherwise
|
||||
defer until after all global names are defined in order to avoid
|
||||
spurious complaints about missing modules."""
|
||||
if caller is not packageModule:
|
||||
deferredImports.append((packageModule, fromList))
|
||||
else:
|
||||
if fromList == ("*",):
|
||||
fromList = packageModule.allNames
|
||||
for name in fromList:
|
||||
if name in packageModule.globalNames:
|
||||
continue
|
||||
subModuleName = "%s.%s" % (packageModule.name, name)
|
||||
self._ImportModule(subModuleName, deferredImports, caller)
|
||||
|
||||
def _FindModule(self, name, path):
|
||||
try:
|
||||
return imp.find_module(name, path)
|
||||
except ImportError:
|
||||
if not path:
|
||||
path = []
|
||||
for location in path:
|
||||
if name in self._zipFileEntries:
|
||||
break
|
||||
if location in self._zipFiles:
|
||||
continue
|
||||
if os.path.isdir(location) or not zipfile.is_zipfile(location):
|
||||
self._zipFiles[location] = None
|
||||
continue
|
||||
zip = zipfile.ZipFile(location)
|
||||
for archiveName in zip.namelist():
|
||||
baseName, ext = os.path.splitext(archiveName)
|
||||
if ext not in ('.pyc', '.pyo'):
|
||||
continue
|
||||
moduleName = ".".join(baseName.split("/"))
|
||||
if moduleName in self._zipFileEntries:
|
||||
continue
|
||||
self._zipFileEntries[moduleName] = (zip, archiveName)
|
||||
self._zipFiles[location] = None
|
||||
info = self._zipFileEntries.get(name)
|
||||
if info is not None:
|
||||
zip, archiveName = info
|
||||
fp = zip.read(archiveName)
|
||||
info = (".pyc", "rb", imp.PY_COMPILED)
|
||||
return fp, os.path.join(zip.filename, archiveName), info
|
||||
raise
|
||||
|
||||
def _GetParentByName(self, name):
|
||||
"""Return the parent module given the name of a module."""
|
||||
pos = name.rfind(".")
|
||||
if pos > 0:
|
||||
parentName = name[:pos]
|
||||
return self._modules[parentName]
|
||||
|
||||
def _ImportAllSubModules(self, module, deferredImports, recursive = True):
|
||||
"""Import all sub modules to the given package."""
|
||||
suffixes = dict.fromkeys([s[0] for s in imp.get_suffixes()])
|
||||
for dir in module.path:
|
||||
try:
|
||||
fileNames = os.listdir(dir)
|
||||
except os.error:
|
||||
continue
|
||||
for fileName in fileNames:
|
||||
name, ext = os.path.splitext(fileName)
|
||||
if ext not in suffixes:
|
||||
continue
|
||||
if name == "__init__":
|
||||
continue
|
||||
subModuleName = "%s.%s" % (module.name, name)
|
||||
subModule, returnError = \
|
||||
self._InternalImportModule(subModuleName,
|
||||
deferredImports)
|
||||
if returnError and subModule is None:
|
||||
raise ImportError, "No module named %s" % subModuleName
|
||||
module.globalNames[name] = None
|
||||
if subModule.path and recursive:
|
||||
self._ImportAllSubModules(subModule, deferredImports,
|
||||
recursive)
|
||||
|
||||
def _ImportDeferredImports(self, deferredImports):
|
||||
"""Import any sub modules that were deferred, if applicable."""
|
||||
while deferredImports:
|
||||
newDeferredImports = []
|
||||
for packageModule, subModuleNames in deferredImports:
|
||||
self._EnsureFromList(packageModule, packageModule,
|
||||
subModuleNames, newDeferredImports)
|
||||
deferredImports = newDeferredImports
|
||||
|
||||
def _ImportModule(self, name, deferredImports, caller = None,
|
||||
relativeImportIndex = 0):
|
||||
"""Attempt to find the named module and return it or None if no module
|
||||
by that name could be found."""
|
||||
|
||||
# absolute import (available in Python 2.5 and up)
|
||||
# the name given is the only name that will be searched
|
||||
if relativeImportIndex == 0:
|
||||
module, returnError = self._InternalImportModule(name,
|
||||
deferredImports)
|
||||
|
||||
# old style relative import (only possibility in Python 2.4 and prior)
|
||||
# the name given is tried in all parents until a match is found and if
|
||||
# no match is found, the global namespace is searched
|
||||
elif relativeImportIndex < 0:
|
||||
parent = self._DetermineParent(caller)
|
||||
while parent is not None:
|
||||
fullName = "%s.%s" % (parent.name, name)
|
||||
module, returnError = self._InternalImportModule(fullName,
|
||||
deferredImports)
|
||||
if module is not None:
|
||||
parent.globalNames[name] = None
|
||||
return module
|
||||
parent = self._GetParentByName(parent.name)
|
||||
module, returnError = self._InternalImportModule(name,
|
||||
deferredImports)
|
||||
|
||||
# new style relative import (available in Python 2.5 and up)
|
||||
# the index indicates how many levels to traverse and only that level
|
||||
# is searched for the named module
|
||||
elif relativeImportIndex > 0:
|
||||
parent = caller
|
||||
if parent.path is not None:
|
||||
relativeImportIndex -= 1
|
||||
while parent is not None and relativeImportIndex > 0:
|
||||
parent = self._GetParentByName(parent.name)
|
||||
relativeImportIndex -= 1
|
||||
if parent is None:
|
||||
module = None
|
||||
returnError = True
|
||||
elif not name:
|
||||
module = parent
|
||||
else:
|
||||
name = "%s.%s" % (parent.name, name)
|
||||
module, returnError = self._InternalImportModule(name,
|
||||
deferredImports)
|
||||
|
||||
# if module not found, track that fact
|
||||
if module is None:
|
||||
if caller is None:
|
||||
raise ImportError, "No module named %s" % name
|
||||
self._RunHook("missing", name, caller)
|
||||
if returnError and name not in caller.ignoreNames:
|
||||
callers = self._badModules.setdefault(name, {})
|
||||
callers[caller.name] = None
|
||||
|
||||
return module
|
||||
|
||||
def _InternalImportModule(self, name, deferredImports):
|
||||
"""Internal method used for importing a module which assumes that the
|
||||
name given is an absolute name. None is returned if the module
|
||||
cannot be found."""
|
||||
try:
|
||||
return self._modules[name], False
|
||||
except KeyError:
|
||||
pass
|
||||
if name in self._builtinModules:
|
||||
module = self._AddModule(name)
|
||||
self._RunHook("load", module.name, module)
|
||||
return module, False
|
||||
pos = name.rfind(".")
|
||||
if pos < 0:
|
||||
path = self.path
|
||||
searchName = name
|
||||
parentModule = None
|
||||
else:
|
||||
parentName = name[:pos]
|
||||
parentModule, returnError = \
|
||||
self._InternalImportModule(parentName, deferredImports)
|
||||
if parentModule is None:
|
||||
return None, returnError
|
||||
path = parentModule.path
|
||||
searchName = name[pos + 1:]
|
||||
if name in self.aliases:
|
||||
actualName = self.aliases[name]
|
||||
module, returnError = \
|
||||
self._InternalImportModule(actualName, deferredImports)
|
||||
self._modules[name] = module
|
||||
return module, returnError
|
||||
try:
|
||||
fp, path, info = self._FindModule(searchName, path)
|
||||
except ImportError:
|
||||
self._modules[name] = None
|
||||
return None, True
|
||||
module = self._LoadModule(name, fp, path, info, deferredImports,
|
||||
parentModule)
|
||||
return module, False
|
||||
|
||||
def _LoadModule(self, name, fp, path, info, deferredImports,
|
||||
parent = None):
|
||||
"""Load the module, given the information acquired by the finder."""
|
||||
suffix, mode, type = info
|
||||
if type == imp.PKG_DIRECTORY:
|
||||
return self._LoadPackage(name, path, parent, deferredImports)
|
||||
module = self._AddModule(name)
|
||||
module.file = path
|
||||
module.parent = parent
|
||||
if type == imp.PY_SOURCE:
|
||||
module.code = compile(fp.read() + "\n", path, "exec")
|
||||
elif type == imp.PY_COMPILED:
|
||||
if isinstance(fp, str):
|
||||
magic = fp[:4]
|
||||
else:
|
||||
magic = fp.read(4)
|
||||
if magic != imp.get_magic():
|
||||
raise ImportError, "Bad magic number in %s" % path
|
||||
if isinstance(fp, str):
|
||||
module.code = marshal.loads(fp[8:])
|
||||
module.inZipFile = True
|
||||
else:
|
||||
fp.read(4)
|
||||
module.code = marshal.load(fp)
|
||||
self._RunHook("load", module.name, module)
|
||||
if module.code is not None:
|
||||
if self.replacePaths:
|
||||
topLevelModule = module
|
||||
while topLevelModule.parent is not None:
|
||||
topLevelModule = topLevelModule.parent
|
||||
module.code = self._ReplacePathsInCode(topLevelModule,
|
||||
module.code)
|
||||
self._ScanCode(module.code, module, deferredImports)
|
||||
return module
|
||||
|
||||
def _LoadPackage(self, name, path, parent, deferredImports):
|
||||
"""Load the package, given its name and path."""
|
||||
module = self._AddModule(name)
|
||||
module.path = [path]
|
||||
fp, path, info = imp.find_module("__init__", module.path)
|
||||
self._LoadModule(name, fp, path, info, deferredImports, parent)
|
||||
return module
|
||||
|
||||
def _ReplacePathsInCode(self, topLevelModule, co):
|
||||
"""Replace paths in the code as directed, returning a new code object
|
||||
with the modified paths in place."""
|
||||
origFileName = newFileName = os.path.normpath(co.co_filename)
|
||||
for searchValue, replaceValue in self.replacePaths:
|
||||
if searchValue == "*":
|
||||
searchValue = os.path.dirname(topLevelModule.file)
|
||||
if topLevelModule.path:
|
||||
searchValue = os.path.dirname(searchValue)
|
||||
if searchValue:
|
||||
searchValue = searchValue + os.pathsep
|
||||
elif not origFileName.startswith(searchValue):
|
||||
continue
|
||||
newFileName = replaceValue + origFileName[len(searchValue):]
|
||||
break
|
||||
constants = list(co.co_consts)
|
||||
for i, value in enumerate(constants):
|
||||
if isinstance(value, type(co)):
|
||||
constants[i] = self._ReplacePathsInCode(topLevelModule, value)
|
||||
return new.code(co.co_argcount, co.co_nlocals, co.co_stacksize,
|
||||
co.co_flags, co.co_code, tuple(constants), co.co_names,
|
||||
co.co_varnames, newFileName, co.co_name, co.co_firstlineno,
|
||||
co.co_lnotab, co.co_freevars, co.co_cellvars)
|
||||
|
||||
def _RunHook(self, hookName, moduleName, *args):
|
||||
"""Run hook for the given module if one is present."""
|
||||
name = "%s_%s" % (hookName, moduleName.replace(".", "_"))
|
||||
method = getattr(cx_Freeze.hooks, name, None)
|
||||
if method is not None:
|
||||
method(self, *args)
|
||||
|
||||
def _ScanCode(self, co, module, deferredImports):
|
||||
"""Scan code, looking for imported modules and keeping track of the
|
||||
constants that have been created in order to better tell which
|
||||
modules are truly missing."""
|
||||
opIndex = 0
|
||||
arguments = []
|
||||
code = co.co_code
|
||||
numOps = len(code)
|
||||
while opIndex < numOps:
|
||||
op = ord(code[opIndex])
|
||||
opIndex += 1
|
||||
if op >= dis.HAVE_ARGUMENT:
|
||||
opArg = ord(code[opIndex]) + ord(code[opIndex + 1]) * 256
|
||||
opIndex += 2
|
||||
if op == LOAD_CONST:
|
||||
arguments.append(co.co_consts[opArg])
|
||||
elif op == IMPORT_NAME:
|
||||
name = co.co_names[opArg]
|
||||
if len(arguments) == 2:
|
||||
relativeImportIndex, fromList = arguments
|
||||
else:
|
||||
relativeImportIndex = -1
|
||||
fromList, = arguments
|
||||
if name not in module.excludeNames:
|
||||
subModule = self._ImportModule(name, deferredImports,
|
||||
module, relativeImportIndex)
|
||||
if subModule is not None:
|
||||
module.globalNames.update(subModule.globalNames)
|
||||
if fromList and subModule.path is not None:
|
||||
self._EnsureFromList(module, subModule, fromList,
|
||||
deferredImports)
|
||||
elif op == IMPORT_FROM:
|
||||
opIndex += 3
|
||||
elif op not in (BUILD_LIST, INPLACE_ADD):
|
||||
if op in STORE_OPS:
|
||||
name = co.co_names[opArg]
|
||||
if name == "__all__":
|
||||
module.allNames.extend(arguments)
|
||||
module.globalNames[name] = None
|
||||
arguments = []
|
||||
for constant in co.co_consts:
|
||||
if isinstance(constant, type(co)):
|
||||
self._ScanCode(constant, module, deferredImports)
|
||||
|
||||
def AddAlias(self, name, aliasFor):
|
||||
"""Add an alias for a particular module; when an attempt is made to
|
||||
import a module using the alias name, import the actual name
|
||||
instead."""
|
||||
self.aliases[name] = aliasFor
|
||||
|
||||
def ExcludeModule(self, name):
|
||||
"""Exclude the named module from the resulting frozen executable."""
|
||||
self.excludes[name] = None
|
||||
self._modules[name] = None
|
||||
|
||||
def IncludeFile(self, path, moduleName = None):
|
||||
"""Include the named file as a module in the frozen executable."""
|
||||
name, ext = os.path.splitext(os.path.basename(path))
|
||||
if moduleName is None:
|
||||
moduleName = name
|
||||
info = (ext, "r", imp.PY_SOURCE)
|
||||
deferredImports = []
|
||||
module = self._LoadModule(moduleName, file(path, "U"), path, info,
|
||||
deferredImports)
|
||||
self._ImportDeferredImports(deferredImports)
|
||||
return module
|
||||
|
||||
def IncludeFiles(self, sourcePath, targetPath):
|
||||
"""Include the files in the given directory in the target build."""
|
||||
self.includeFiles.append((sourcePath, targetPath))
|
||||
|
||||
def IncludeModule(self, name):
|
||||
"""Include the named module in the frozen executable."""
|
||||
deferredImports = []
|
||||
module = self._ImportModule(name, deferredImports)
|
||||
self._ImportDeferredImports(deferredImports)
|
||||
return module
|
||||
|
||||
def IncludePackage(self, name):
|
||||
"""Include the named package and any submodules in the frozen
|
||||
executable."""
|
||||
deferredImports = []
|
||||
module = self._ImportModule(name, deferredImports)
|
||||
if module.path:
|
||||
self._ImportAllSubModules(module, deferredImports)
|
||||
self._ImportDeferredImports(deferredImports)
|
||||
return module
|
||||
|
||||
def ReportMissingModules(self):
|
||||
if self._badModules:
|
||||
print "Missing modules:"
|
||||
names = self._badModules.keys()
|
||||
names.sort()
|
||||
for name in names:
|
||||
callers = self._badModules[name].keys()
|
||||
callers.sort()
|
||||
print "?", name, "imported from", ", ".join(callers)
|
||||
print
|
||||
|
||||
|
||||
class Module(object):
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.file = None
|
||||
self.path = None
|
||||
self.code = None
|
||||
self.parent = None
|
||||
self.globalNames = {}
|
||||
self.excludeNames = {}
|
||||
self.ignoreNames = {}
|
||||
self.allNames = []
|
||||
self.inZipFile = False
|
||||
|
||||
def __repr__(self):
|
||||
parts = ["name=%s" % repr(self.name)]
|
||||
if self.file is not None:
|
||||
parts.append("file=%s" % repr(self.file))
|
||||
if self.path is not None:
|
||||
parts.append("path=%s" % repr(self.path))
|
||||
return "<Module %s>" % ", ".join(parts)
|
||||
|
||||
def AddGlobalName(self, name):
|
||||
self.globalNames[name] = None
|
||||
|
||||
def ExcludeName(self, name):
|
||||
self.excludeNames[name] = None
|
||||
|
||||
def IgnoreName(self, name):
|
||||
self.ignoreNames[name] = None
|
||||
|
@ -1,550 +0,0 @@
|
||||
"""
|
||||
Base class for freezing scripts into executables.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
import distutils.sysconfig
|
||||
import imp
|
||||
import marshal
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
import stat
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
import cx_Freeze
|
||||
import cx_Freeze.util
|
||||
|
||||
__all__ = [ "ConfigError", "ConstantsModule", "Executable", "Freezer" ]
|
||||
|
||||
if sys.platform == "win32":
|
||||
pythonDll = "python%s%s.dll" % sys.version_info[:2]
|
||||
GLOBAL_BIN_PATH_EXCLUDES = [cx_Freeze.util.GetSystemDir()]
|
||||
GLOBAL_BIN_INCLUDES = [
|
||||
pythonDll,
|
||||
"gdiplus.dll",
|
||||
"mfc71.dll",
|
||||
"msvcp71.dll",
|
||||
"msvcr71.dll"
|
||||
]
|
||||
GLOBAL_BIN_EXCLUDES = [
|
||||
"comctl32.dll",
|
||||
"oci.dll",
|
||||
"cx_Logging.pyd"
|
||||
]
|
||||
else:
|
||||
extension = distutils.sysconfig.get_config_var("SO")
|
||||
pythonSharedLib = "libpython%s.%s%s" % \
|
||||
(sys.version_info[:2] + (extension,))
|
||||
GLOBAL_BIN_INCLUDES = [pythonSharedLib]
|
||||
GLOBAL_BIN_EXCLUDES = [
|
||||
"libclntsh.so",
|
||||
"libwtc9.so"
|
||||
]
|
||||
GLOBAL_BIN_PATH_EXCLUDES = ["/lib", "/lib32", "/lib64", "/usr/lib",
|
||||
"/usr/lib32", "/usr/lib64"]
|
||||
|
||||
|
||||
# NOTE: the try: except: block in this code is not necessary under Python 2.4
|
||||
# and higher and can be removed once support for Python 2.3 is no longer needed
|
||||
EXTENSION_LOADER_SOURCE = \
|
||||
"""
|
||||
import imp, os, sys
|
||||
|
||||
found = False
|
||||
for p in sys.path:
|
||||
if not os.path.isdir(p):
|
||||
continue
|
||||
f = os.path.join(p, "%s")
|
||||
if not os.path.exists(f):
|
||||
continue
|
||||
try:
|
||||
m = imp.load_dynamic(__name__, f)
|
||||
except ImportError:
|
||||
del sys.modules[__name__]
|
||||
raise
|
||||
sys.modules[__name__] = m
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
del sys.modules[__name__]
|
||||
raise ImportError, "No module named %%s" %% __name__
|
||||
"""
|
||||
|
||||
|
||||
class Freezer(object):
|
||||
|
||||
def __init__(self, executables, constantsModules = [], includes = [],
|
||||
excludes = [], packages = [], replacePaths = [], compress = None,
|
||||
optimizeFlag = 0, copyDependentFiles = None, initScript = None,
|
||||
base = None, path = None, createLibraryZip = None,
|
||||
appendScriptToExe = None, appendScriptToLibrary = None,
|
||||
targetDir = None, binIncludes = [], binExcludes = [],
|
||||
binPathIncludes = [], binPathExcludes = [], icon = None,
|
||||
includeFiles = []):
|
||||
self.executables = executables
|
||||
self.constantsModules = constantsModules
|
||||
self.includes = includes
|
||||
self.excludes = excludes
|
||||
self.packages = packages
|
||||
self.replacePaths = replacePaths
|
||||
self.compress = compress
|
||||
self.optimizeFlag = optimizeFlag
|
||||
self.copyDependentFiles = copyDependentFiles
|
||||
self.initScript = initScript
|
||||
self.base = base
|
||||
self.path = path
|
||||
self.createLibraryZip = createLibraryZip
|
||||
self.appendScriptToExe = appendScriptToExe
|
||||
self.appendScriptToLibrary = appendScriptToLibrary
|
||||
self.targetDir = targetDir
|
||||
self.binIncludes = [os.path.normcase(n) \
|
||||
for n in GLOBAL_BIN_INCLUDES + binIncludes]
|
||||
self.binExcludes = [os.path.normcase(n) \
|
||||
for n in GLOBAL_BIN_EXCLUDES + binExcludes]
|
||||
self.binPathIncludes = [os.path.normcase(n) for n in binPathIncludes]
|
||||
self.binPathExcludes = [os.path.normcase(n) \
|
||||
for n in GLOBAL_BIN_PATH_EXCLUDES + binPathExcludes]
|
||||
self.icon = icon
|
||||
self.includeFiles = includeFiles
|
||||
self._VerifyConfiguration()
|
||||
|
||||
def _CopyFile(self, source, target, copyDependentFiles,
|
||||
includeMode = False):
|
||||
normalizedSource = os.path.normcase(os.path.normpath(source))
|
||||
normalizedTarget = os.path.normcase(os.path.normpath(target))
|
||||
if normalizedTarget in self.filesCopied:
|
||||
return
|
||||
if normalizedSource == normalizedTarget:
|
||||
return
|
||||
self._RemoveFile(target)
|
||||
targetDir = os.path.dirname(target)
|
||||
self._CreateDirectory(targetDir)
|
||||
print "copying", source, "->", target
|
||||
shutil.copyfile(source, target)
|
||||
if includeMode:
|
||||
shutil.copymode(source, target)
|
||||
self.filesCopied[normalizedTarget] = None
|
||||
if copyDependentFiles:
|
||||
for source in self._GetDependentFiles(source):
|
||||
target = os.path.join(targetDir, os.path.basename(source))
|
||||
self._CopyFile(source, target, copyDependentFiles)
|
||||
|
||||
def _CreateDirectory(self, path):
|
||||
if not os.path.isdir(path):
|
||||
print "creating directory", path
|
||||
os.makedirs(path)
|
||||
|
||||
def _FreezeExecutable(self, exe):
|
||||
if self.createLibraryZip:
|
||||
finder = self.finder
|
||||
else:
|
||||
finder = self._GetModuleFinder(exe)
|
||||
if exe.script is None:
|
||||
scriptModule = None
|
||||
else:
|
||||
scriptModule = finder.IncludeFile(exe.script, exe.moduleName)
|
||||
self._CopyFile(exe.base, exe.targetName, exe.copyDependentFiles,
|
||||
includeMode = True)
|
||||
if exe.icon is not None:
|
||||
if sys.platform == "win32":
|
||||
cx_Freeze.util.AddIcon(exe.targetName, exe.icon)
|
||||
else:
|
||||
targetName = os.path.join(os.path.dirname(exe.targetName),
|
||||
os.path.basename(exe.icon))
|
||||
self._CopyFile(exe.icon, targetName,
|
||||
copyDependentFiles = False)
|
||||
if not os.access(exe.targetName, os.W_OK):
|
||||
mode = os.stat(exe.targetName).st_mode
|
||||
os.chmod(exe.targetName, mode | stat.S_IWUSR)
|
||||
if not exe.appendScriptToLibrary:
|
||||
if exe.appendScriptToExe:
|
||||
fileName = exe.targetName
|
||||
else:
|
||||
baseFileName, ext = os.path.splitext(exe.targetName)
|
||||
fileName = baseFileName + ".zip"
|
||||
self._RemoveFile(fileName)
|
||||
if not self.createLibraryZip and exe.copyDependentFiles:
|
||||
scriptModule = None
|
||||
self._WriteModules(fileName, exe.initScript, finder, exe.compress,
|
||||
exe.copyDependentFiles, scriptModule)
|
||||
|
||||
def _GetBaseFileName(self, argsSource = None):
|
||||
if argsSource is None:
|
||||
argsSource = self
|
||||
name = argsSource.base
|
||||
if name is None:
|
||||
if argsSource.copyDependentFiles:
|
||||
name = "Console"
|
||||
else:
|
||||
name = "ConsoleKeepPath"
|
||||
argsSource.base = self._GetFileName("bases", name)
|
||||
if argsSource.base is None:
|
||||
raise ConfigError("no base named %s", name)
|
||||
|
||||
def _GetDependentFiles(self, path):
|
||||
dependentFiles = self.dependentFiles.get(path)
|
||||
if dependentFiles is None:
|
||||
if sys.platform == "win32":
|
||||
origPath = os.environ["PATH"]
|
||||
os.environ["PATH"] = origPath + os.pathsep + \
|
||||
os.pathsep.join(sys.path)
|
||||
dependentFiles = cx_Freeze.util.GetDependentFiles(path)
|
||||
os.environ["PATH"] = origPath
|
||||
else:
|
||||
dependentFiles = []
|
||||
for line in os.popen('ldd "%s"' % path):
|
||||
parts = line.strip().split(" => ")
|
||||
if len(parts) != 2:
|
||||
continue
|
||||
dependentFile = parts[1]
|
||||
if dependentFile == "not found":
|
||||
print "WARNING: cannot find", parts[0]
|
||||
continue
|
||||
pos = dependentFile.find(" (")
|
||||
if pos >= 0:
|
||||
dependentFile = dependentFile[:pos].strip()
|
||||
if dependentFile:
|
||||
dependentFiles.append(dependentFile)
|
||||
dependentFiles = self.dependentFiles[path] = \
|
||||
[f for f in dependentFiles if self._ShouldCopyFile(f)]
|
||||
return dependentFiles
|
||||
|
||||
def _GetFileName(self, dir, name):
|
||||
if os.path.isabs(name):
|
||||
return name
|
||||
name = os.path.normcase(name)
|
||||
fullDir = os.path.join(os.path.dirname(cx_Freeze.__file__), dir)
|
||||
if os.path.isdir(fullDir):
|
||||
for fileName in os.listdir(fullDir):
|
||||
if name == os.path.splitext(os.path.normcase(fileName))[0]:
|
||||
return os.path.join(fullDir, fileName)
|
||||
|
||||
def _GetInitScriptFileName(self, argsSource = None):
|
||||
if argsSource is None:
|
||||
argsSource = self
|
||||
name = argsSource.initScript
|
||||
if name is None:
|
||||
if argsSource.copyDependentFiles:
|
||||
name = "Console"
|
||||
else:
|
||||
name = "ConsoleKeepPath"
|
||||
argsSource.initScript = self._GetFileName("initscripts", name)
|
||||
if argsSource.initScript is None:
|
||||
raise ConfigError("no initscript named %s", name)
|
||||
|
||||
def _GetModuleFinder(self, argsSource = None):
|
||||
if argsSource is None:
|
||||
argsSource = self
|
||||
finder = cx_Freeze.ModuleFinder(self.includeFiles, argsSource.excludes,
|
||||
argsSource.path, argsSource.replacePaths)
|
||||
if argsSource.copyDependentFiles:
|
||||
finder.IncludeModule("imp")
|
||||
finder.IncludeModule("os")
|
||||
finder.IncludeModule("sys")
|
||||
if argsSource.compress:
|
||||
finder.IncludeModule("zlib")
|
||||
for name in argsSource.includes:
|
||||
finder.IncludeModule(name)
|
||||
for name in argsSource.packages:
|
||||
finder.IncludePackage(name)
|
||||
return finder
|
||||
|
||||
def _PrintReport(self, fileName, modules):
|
||||
print "writing zip file", fileName
|
||||
print
|
||||
print " %-25s %s" % ("Name", "File")
|
||||
print " %-25s %s" % ("----", "----")
|
||||
for module in modules:
|
||||
if module.path:
|
||||
print "P",
|
||||
else:
|
||||
print "m",
|
||||
print "%-25s" % module.name, module.file or ""
|
||||
print
|
||||
|
||||
def _RemoveFile(self, path):
|
||||
if os.path.exists(path):
|
||||
os.chmod(path, 0777)
|
||||
os.remove(path)
|
||||
|
||||
def _ShouldCopyFile(self, path):
|
||||
dir, name = os.path.split(os.path.normcase(path))
|
||||
parts = name.split(".")
|
||||
tweaked = False
|
||||
while True:
|
||||
if not parts[-1].isdigit():
|
||||
break
|
||||
parts.pop(-1)
|
||||
tweaked = True
|
||||
if tweaked:
|
||||
name = ".".join(parts)
|
||||
if name in self.binIncludes:
|
||||
return True
|
||||
if name in self.binExcludes:
|
||||
return False
|
||||
for path in self.binPathIncludes:
|
||||
if dir.startswith(path):
|
||||
return True
|
||||
for path in self.binPathExcludes:
|
||||
if dir.startswith(path):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _VerifyCanAppendToLibrary(self):
|
||||
if not self.createLibraryZip:
|
||||
raise ConfigError("script cannot be appended to library zip if "
|
||||
"one is not being created")
|
||||
|
||||
def _VerifyConfiguration(self):
|
||||
if self.compress is None:
|
||||
self.compress = True
|
||||
if self.copyDependentFiles is None:
|
||||
self.copyDependentFiles = True
|
||||
if self.createLibraryZip is None:
|
||||
self.createLibraryZip = True
|
||||
if self.appendScriptToExe is None:
|
||||
self.appendScriptToExe = False
|
||||
if self.appendScriptToLibrary is None:
|
||||
self.appendScriptToLibrary = \
|
||||
self.createLibraryZip and not self.appendScriptToExe
|
||||
if self.targetDir is None:
|
||||
self.targetDir = os.path.abspath("dist")
|
||||
self._GetInitScriptFileName()
|
||||
self._GetBaseFileName()
|
||||
if self.path is None:
|
||||
self.path = sys.path
|
||||
if self.appendScriptToLibrary:
|
||||
self._VerifyCanAppendToLibrary()
|
||||
for sourceFileName, targetFileName in self.includeFiles:
|
||||
if not os.path.exists(sourceFileName):
|
||||
raise ConfigError("cannot find file/directory named %s",
|
||||
sourceFileName)
|
||||
if os.path.isabs(targetFileName):
|
||||
raise ConfigError("target file/directory cannot be absolute")
|
||||
for executable in self.executables:
|
||||
executable._VerifyConfiguration(self)
|
||||
|
||||
def _WriteModules(self, fileName, initScript, finder, compress,
|
||||
copyDependentFiles, scriptModule = None):
|
||||
initModule = finder.IncludeFile(initScript, "cx_Freeze__init__")
|
||||
if scriptModule is None:
|
||||
for module in self.constantsModules:
|
||||
module.Create(finder)
|
||||
modules = [m for m in finder.modules \
|
||||
if m.name not in self.excludeModules]
|
||||
else:
|
||||
modules = [initModule, scriptModule]
|
||||
self.excludeModules[initModule.name] = None
|
||||
self.excludeModules[scriptModule.name] = None
|
||||
itemsToSort = [(m.name, m) for m in modules]
|
||||
itemsToSort.sort()
|
||||
modules = [m for n, m in itemsToSort]
|
||||
self._PrintReport(fileName, modules)
|
||||
if scriptModule is None:
|
||||
finder.ReportMissingModules()
|
||||
targetDir = os.path.dirname(fileName)
|
||||
self._CreateDirectory(targetDir)
|
||||
filesToCopy = []
|
||||
if os.path.exists(fileName):
|
||||
mode = "a"
|
||||
else:
|
||||
mode = "w"
|
||||
outFile = zipfile.PyZipFile(fileName, mode, zipfile.ZIP_DEFLATED)
|
||||
for module in modules:
|
||||
if module.code is None and module.file is not None:
|
||||
fileName = os.path.basename(module.file)
|
||||
baseFileName, ext = os.path.splitext(fileName)
|
||||
if baseFileName != module.name and module.name != "zlib":
|
||||
if "." in module.name:
|
||||
fileName = module.name + ext
|
||||
generatedFileName = "ExtensionLoader_%s.py" % \
|
||||
module.name.replace(".", "_")
|
||||
module.code = compile(EXTENSION_LOADER_SOURCE % fileName,
|
||||
generatedFileName, "exec")
|
||||
target = os.path.join(targetDir, fileName)
|
||||
filesToCopy.append((module, target))
|
||||
if module.code is None:
|
||||
continue
|
||||
fileName = "/".join(module.name.split("."))
|
||||
if module.path:
|
||||
fileName += "/__init__"
|
||||
if module.file is not None and os.path.exists(module.file):
|
||||
mtime = os.stat(module.file).st_mtime
|
||||
else:
|
||||
mtime = time.time()
|
||||
zipTime = time.localtime(mtime)[:6]
|
||||
data = imp.get_magic() + struct.pack("<i", mtime) + \
|
||||
marshal.dumps(module.code)
|
||||
zinfo = zipfile.ZipInfo(fileName + ".pyc", zipTime)
|
||||
if compress:
|
||||
zinfo.compress_type = zipfile.ZIP_DEFLATED
|
||||
outFile.writestr(zinfo, data)
|
||||
origPath = os.environ["PATH"]
|
||||
for module, target in filesToCopy:
|
||||
try:
|
||||
if module.parent is not None:
|
||||
path = os.pathsep.join([origPath] + module.parent.path)
|
||||
os.environ["PATH"] = path
|
||||
self._CopyFile(module.file, target, copyDependentFiles)
|
||||
finally:
|
||||
os.environ["PATH"] = origPath
|
||||
|
||||
def Freeze(self):
|
||||
self.finder = None
|
||||
self.excludeModules = {}
|
||||
self.dependentFiles = {}
|
||||
self.filesCopied = {}
|
||||
cx_Freeze.util.SetOptimizeFlag(self.optimizeFlag)
|
||||
if self.createLibraryZip:
|
||||
self.finder = self._GetModuleFinder()
|
||||
for executable in self.executables:
|
||||
self._FreezeExecutable(executable)
|
||||
if self.createLibraryZip:
|
||||
fileName = os.path.join(self.targetDir, "library.zip")
|
||||
self._RemoveFile(fileName)
|
||||
self._WriteModules(fileName, self.initScript, self.finder,
|
||||
self.compress, self.copyDependentFiles)
|
||||
for sourceFileName, targetFileName in self.includeFiles:
|
||||
fullName = os.path.join(self.targetDir, targetFileName)
|
||||
if os.path.isdir(sourceFileName):
|
||||
for path, dirNames, fileNames in os.walk(sourceFileName):
|
||||
shortPath = path[len(sourceFileName) + 1:]
|
||||
if ".svn" in dirNames:
|
||||
dirNames.remove(".svn")
|
||||
if "CVS" in dirNames:
|
||||
dirNames.remove("CVS")
|
||||
for fileName in fileNames:
|
||||
fullSourceName = os.path.join(path, fileName)
|
||||
fullTargetName = os.path.join(self.targetDir,
|
||||
targetFileName, shortPath, fileName)
|
||||
self._CopyFile(fullSourceName, fullTargetName,
|
||||
copyDependentFiles = False)
|
||||
else:
|
||||
self._CopyFile(sourceFileName, fullName,
|
||||
copyDependentFiles = False)
|
||||
|
||||
|
||||
class ConfigError(Exception):
|
||||
|
||||
def __init__(self, format, *args):
|
||||
self.what = format % args
|
||||
|
||||
def __str__(self):
|
||||
return self.what
|
||||
|
||||
|
||||
class Executable(object):
|
||||
|
||||
def __init__(self, script, initScript = None, base = None, path = None,
|
||||
targetDir = None, targetName = None, includes = None,
|
||||
excludes = None, packages = None, replacePaths = None,
|
||||
compress = None, copyDependentFiles = None,
|
||||
appendScriptToExe = None, appendScriptToLibrary = None,
|
||||
icon = None):
|
||||
self.script = script
|
||||
self.initScript = initScript
|
||||
self.base = base
|
||||
self.path = path
|
||||
self.targetDir = targetDir
|
||||
self.targetName = targetName
|
||||
self.includes = includes
|
||||
self.excludes = excludes
|
||||
self.packages = packages
|
||||
self.replacePaths = replacePaths
|
||||
self.compress = compress
|
||||
self.copyDependentFiles = copyDependentFiles
|
||||
self.appendScriptToExe = appendScriptToExe
|
||||
self.appendScriptToLibrary = appendScriptToLibrary
|
||||
self.icon = icon
|
||||
|
||||
def __repr__(self):
|
||||
return "<Executable script=%s>" % self.script
|
||||
|
||||
def _VerifyConfiguration(self, freezer):
|
||||
if self.path is None:
|
||||
self.path = freezer.path
|
||||
if self.targetDir is None:
|
||||
self.targetDir = freezer.targetDir
|
||||
if self.includes is None:
|
||||
self.includes = freezer.includes
|
||||
if self.excludes is None:
|
||||
self.excludes = freezer.excludes
|
||||
if self.packages is None:
|
||||
self.packages = freezer.packages
|
||||
if self.replacePaths is None:
|
||||
self.replacePaths = freezer.replacePaths
|
||||
if self.compress is None:
|
||||
self.compress = freezer.compress
|
||||
if self.copyDependentFiles is None:
|
||||
self.copyDependentFiles = freezer.copyDependentFiles
|
||||
if self.appendScriptToExe is None:
|
||||
self.appendScriptToExe = freezer.appendScriptToExe
|
||||
if self.appendScriptToLibrary is None:
|
||||
self.appendScriptToLibrary = freezer.appendScriptToLibrary
|
||||
if self.initScript is None:
|
||||
self.initScript = freezer.initScript
|
||||
else:
|
||||
freezer._GetInitScriptFileName(self)
|
||||
if self.base is None:
|
||||
self.base = freezer.base
|
||||
else:
|
||||
freezer._GetBaseFileName(self)
|
||||
if self.appendScriptToLibrary:
|
||||
freezer._VerifyCanAppendToLibrary()
|
||||
if self.icon is None:
|
||||
self.icon = freezer.icon
|
||||
if self.script is not None:
|
||||
name, ext = os.path.splitext(os.path.basename(self.script))
|
||||
if self.appendScriptToLibrary:
|
||||
self.moduleName = "%s__main__" % os.path.normcase(name)
|
||||
else:
|
||||
self.moduleName = "__main__"
|
||||
if self.targetName is None:
|
||||
baseName, ext = os.path.splitext(self.base)
|
||||
self.targetName = name + ext
|
||||
self.targetName = os.path.join(self.targetDir, self.targetName)
|
||||
|
||||
|
||||
class ConstantsModule(object):
|
||||
|
||||
def __init__(self, releaseString = None, copyright = None,
|
||||
moduleName = "BUILD_CONSTANTS", timeFormat = "%B %d, %Y %H:%M:%S"):
|
||||
self.moduleName = moduleName
|
||||
self.timeFormat = timeFormat
|
||||
self.values = {}
|
||||
self.values["BUILD_RELEASE_STRING"] = releaseString
|
||||
self.values["BUILD_COPYRIGHT"] = copyright
|
||||
|
||||
def Create(self, finder):
|
||||
"""Create the module which consists of declaration statements for each
|
||||
of the values."""
|
||||
today = datetime.datetime.today()
|
||||
sourceTimestamp = 0
|
||||
for module in finder.modules:
|
||||
if module.file is None:
|
||||
continue
|
||||
if module.inZipFile:
|
||||
continue
|
||||
if not os.path.exists(module.file):
|
||||
raise ConfigError("no file named %s", module.file)
|
||||
timestamp = os.stat(module.file).st_mtime
|
||||
sourceTimestamp = max(sourceTimestamp, timestamp)
|
||||
sourceTimestamp = datetime.datetime.fromtimestamp(sourceTimestamp)
|
||||
self.values["BUILD_TIMESTAMP"] = today.strftime(self.timeFormat)
|
||||
self.values["BUILD_HOST"] = socket.gethostname().split(".")[0]
|
||||
self.values["SOURCE_TIMESTAMP"] = \
|
||||
sourceTimestamp.strftime(self.timeFormat)
|
||||
module = finder._AddModule(self.moduleName)
|
||||
sourceParts = []
|
||||
names = self.values.keys()
|
||||
names.sort()
|
||||
for name in names:
|
||||
value = self.values[name]
|
||||
sourceParts.append("%s = %r" % (name, value))
|
||||
source = "\n".join(sourceParts)
|
||||
module.code = compile(source, "%s.py" % self.moduleName, "exec")
|
||||
|
@ -1,281 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
def initialize(finder):
|
||||
"""upon initialization of the finder, this routine is called to set up some
|
||||
automatic exclusions for various platforms."""
|
||||
finder.ExcludeModule("FCNTL")
|
||||
finder.ExcludeModule("os.path")
|
||||
if os.name == "nt":
|
||||
finder.ExcludeModule("fcntl")
|
||||
finder.ExcludeModule("grp")
|
||||
finder.ExcludeModule("pwd")
|
||||
finder.ExcludeModule("termios")
|
||||
else:
|
||||
finder.ExcludeModule("_winreg")
|
||||
finder.ExcludeModule("msilib")
|
||||
finder.ExcludeModule("msvcrt")
|
||||
finder.ExcludeModule("nt")
|
||||
if os.name not in ("os2", "ce"):
|
||||
finder.ExcludeModule("ntpath")
|
||||
finder.ExcludeModule("nturl2path")
|
||||
finder.ExcludeModule("pythoncom")
|
||||
finder.ExcludeModule("pywintypes")
|
||||
finder.ExcludeModule("winerror")
|
||||
finder.ExcludeModule("winsound")
|
||||
finder.ExcludeModule("win32api")
|
||||
finder.ExcludeModule("win32con")
|
||||
finder.ExcludeModule("win32event")
|
||||
finder.ExcludeModule("win32file")
|
||||
finder.ExcludeModule("win32pdh")
|
||||
finder.ExcludeModule("win32pipe")
|
||||
finder.ExcludeModule("win32process")
|
||||
finder.ExcludeModule("win32security")
|
||||
finder.ExcludeModule("win32service")
|
||||
finder.ExcludeModule("wx.activex")
|
||||
if os.name != "posix":
|
||||
finder.ExcludeModule("posix")
|
||||
if os.name != "mac":
|
||||
finder.ExcludeModule("Carbon")
|
||||
finder.ExcludeModule("gestalt")
|
||||
finder.ExcludeModule("ic")
|
||||
finder.ExcludeModule("mac")
|
||||
finder.ExcludeModule("MacOS")
|
||||
finder.ExcludeModule("macpath")
|
||||
finder.ExcludeModule("macurl2path")
|
||||
if os.name != "nt":
|
||||
finder.ExcludeModule("EasyDialogs")
|
||||
if os.name != "os2":
|
||||
finder.ExcludeModule("os2")
|
||||
finder.ExcludeModule("os2emxpath")
|
||||
finder.ExcludeModule("_emx_link")
|
||||
if os.name != "ce":
|
||||
finder.ExcludeModule("ce")
|
||||
if os.name != "riscos":
|
||||
finder.ExcludeModule("riscos")
|
||||
finder.ExcludeModule("riscosenviron")
|
||||
finder.ExcludeModule("riscospath")
|
||||
finder.ExcludeModule("rourl2path")
|
||||
if sys.platform[:4] != "java":
|
||||
finder.ExcludeModule("java.lang")
|
||||
finder.ExcludeModule("org.python.core")
|
||||
|
||||
|
||||
def load_cElementTree(finder, module):
|
||||
"""the cElementTree module implicitly loads the elementtree.ElementTree
|
||||
module; make sure this happens."""
|
||||
finder.IncludeModule("elementtree.ElementTree")
|
||||
|
||||
|
||||
def load_ceODBC(finder, module):
|
||||
"""the ceODBC module implicitly imports both datetime and decimal; make
|
||||
sure this happens."""
|
||||
finder.IncludeModule("datetime")
|
||||
finder.IncludeModule("decimal")
|
||||
|
||||
|
||||
def load_cx_Oracle(finder, module):
|
||||
"""the cx_Oracle module implicitly imports datetime; make sure this
|
||||
happens."""
|
||||
finder.IncludeModule("datetime")
|
||||
|
||||
|
||||
def load_docutils_frontend(finder, module):
|
||||
"""The optik module is the old name for the optparse module; ignore the
|
||||
module if it cannot be found."""
|
||||
module.IgnoreName("optik")
|
||||
|
||||
|
||||
def load_dummy_threading(finder, module):
|
||||
"""the dummy_threading module plays games with the name of the threading
|
||||
module for its own purposes; ignore that here"""
|
||||
finder.ExcludeModule("_dummy_threading")
|
||||
|
||||
|
||||
def load_email(finder, module):
|
||||
"""the email package has a bunch of aliases as the submodule names were
|
||||
all changed to lowercase in Python 2.5; mimic that here."""
|
||||
if sys.version_info[:2] >= (2, 5):
|
||||
for name in ("Charset", "Encoders", "Errors", "FeedParser",
|
||||
"Generator", "Header", "Iterators", "Message", "Parser",
|
||||
"Utils", "base64MIME", "quopriMIME"):
|
||||
finder.AddAlias("email.%s" % name, "email.%s" % name.lower())
|
||||
|
||||
|
||||
def load_ftplib(finder, module):
|
||||
"""the ftplib module attempts to import the SOCKS module; ignore this
|
||||
module if it cannot be found"""
|
||||
module.IgnoreName("SOCKS")
|
||||
|
||||
|
||||
def load_matplotlib(finder, module):
|
||||
"""the matplotlib module requires data to be found in mpl-data in the
|
||||
same directory as the frozen executable so oblige it"""
|
||||
dir = os.path.join(module.path[0], "mpl-data")
|
||||
finder.IncludeFiles(dir, "mpl-data")
|
||||
|
||||
|
||||
def load_matplotlib_numerix(finder, module):
|
||||
"""the numpy.numerix module loads a number of modules dynamically"""
|
||||
for name in ("ma", "fft", "linear_algebra", "random_array", "mlab"):
|
||||
finder.IncludeModule("%s.%s" % (module.name, name))
|
||||
|
||||
|
||||
def load_numpy_linalg(finder, module):
|
||||
"""the numpy.linalg module implicitly loads the lapack_lite module; make
|
||||
sure this happens"""
|
||||
finder.IncludeModule("numpy.linalg.lapack_lite")
|
||||
|
||||
|
||||
def load_pty(finder, module):
|
||||
"""The sgi module is not needed for this module to function."""
|
||||
module.IgnoreName("sgi")
|
||||
|
||||
|
||||
def load_pythoncom(finder, module):
|
||||
"""the pythoncom module is actually contained in a DLL but since those
|
||||
cannot be loaded directly in Python 2.5 and higher a special module is
|
||||
used to perform that task; simply use that technique directly to
|
||||
determine the name of the DLL and ensure it is included as a normal
|
||||
extension; also load the pywintypes module which is implicitly
|
||||
loaded."""
|
||||
import pythoncom
|
||||
module.file = pythoncom.__file__
|
||||
module.code = None
|
||||
finder.IncludeModule("pywintypes")
|
||||
|
||||
|
||||
def load_pywintypes(finder, module):
|
||||
"""the pywintypes module is actually contained in a DLL but since those
|
||||
cannot be loaded directly in Python 2.5 and higher a special module is
|
||||
used to perform that task; simply use that technique directly to
|
||||
determine the name of the DLL and ensure it is included as a normal
|
||||
extension."""
|
||||
import pywintypes
|
||||
module.file = pywintypes.__file__
|
||||
module.code = None
|
||||
|
||||
|
||||
def load_PyQt4_Qt(finder, module):
|
||||
"""the PyQt4.Qt module is an extension module which imports a number of
|
||||
other modules and injects their namespace into its own. It seems a
|
||||
foolish way of doing things but perhaps there is some hidden advantage
|
||||
to this technique over pure Python; ignore the absence of some of
|
||||
the modules since not every installation includes all of them."""
|
||||
finder.IncludeModule("PyQt4.QtCore")
|
||||
finder.IncludeModule("PyQt4.QtGui")
|
||||
finder.IncludeModule("sip")
|
||||
for name in ("PyQt4.QtSvg", "PyQt4.Qsci", "PyQt4.QtAssistant",
|
||||
"PyQt4.QtNetwork", "PyQt4.QtOpenGL", "PyQt4.QtScript", "PyQt4._qt",
|
||||
"PyQt4.QtSql", "PyQt4.QtSvg", "PyQt4.QtTest", "PyQt4.QtXml"):
|
||||
try:
|
||||
finder.IncludeModule(name)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
def load_Tkinter(finder, module):
|
||||
"""the Tkinter module has data files that are required to be loaded so
|
||||
ensure that they are copied into the directory that is expected at
|
||||
runtime."""
|
||||
import Tkinter
|
||||
import _tkinter
|
||||
tk = _tkinter.create()
|
||||
tclDir = os.path.dirname(tk.call("info", "library"))
|
||||
tclSourceDir = os.path.join(tclDir, "tcl%s" % _tkinter.TCL_VERSION)
|
||||
tkSourceDir = os.path.join(tclDir, "tk%s" % _tkinter.TK_VERSION)
|
||||
finder.IncludeFiles(tclSourceDir, "tcl")
|
||||
finder.IncludeFiles(tkSourceDir, "tk")
|
||||
|
||||
|
||||
def load_tempfile(finder, module):
|
||||
"""the tempfile module attempts to load the fcntl and thread modules but
|
||||
continues if these modules cannot be found; ignore these modules if they
|
||||
cannot be found."""
|
||||
module.IgnoreName("fcntl")
|
||||
module.IgnoreName("thread")
|
||||
|
||||
|
||||
def load_time(finder, module):
|
||||
"""the time module implicitly loads _strptime; make sure this happens."""
|
||||
finder.IncludeModule("_strptime")
|
||||
|
||||
|
||||
def load_win32api(finder, module):
|
||||
"""the win32api module implicitly loads the pywintypes module; make sure
|
||||
this happens."""
|
||||
finder.IncludeModule("pywintypes")
|
||||
|
||||
|
||||
def load_win32com(finder, module):
|
||||
"""the win32com package manipulates its search path at runtime to include
|
||||
the sibling directory called win32comext; simulate that by changing the
|
||||
search path in a similar fashion here."""
|
||||
baseDir = os.path.dirname(os.path.dirname(module.file))
|
||||
module.path.append(os.path.join(baseDir, "win32comext"))
|
||||
|
||||
|
||||
def load_win32file(finder, module):
|
||||
"""the win32api module implicitly loads the pywintypes module; make sure
|
||||
this happens."""
|
||||
finder.IncludeModule("pywintypes")
|
||||
|
||||
|
||||
def load_xml(finder, module):
|
||||
"""the builtin xml package attempts to load the _xmlplus module to see if
|
||||
that module should take its role instead; ignore the failure to find
|
||||
this module, though."""
|
||||
module.IgnoreName("_xmlplus")
|
||||
|
||||
|
||||
def load_xml_etree_cElementTree(finder, module):
|
||||
"""the xml.etree.cElementTree module implicitly loads the
|
||||
xml.etree.ElementTree module; make sure this happens."""
|
||||
finder.IncludeModule("xml.etree.ElementTree")
|
||||
|
||||
def load_IPython(finder, module):
|
||||
ipy = os.path.join(os.path.dirname(module.file), 'Extensions')
|
||||
extensions = set([])
|
||||
for m in os.listdir(ipy):
|
||||
extensions.add(os.path.splitext(m)[0])
|
||||
extensions.remove('__init__')
|
||||
for m in extensions:
|
||||
finder.IncludeModule('IPython.Extensions.'+m)
|
||||
|
||||
def load_lxml(finder, module):
|
||||
finder.IncludeModule('lxml._elementpath')
|
||||
|
||||
def load_cherrypy(finder, module):
|
||||
finder.IncludeModule('cherrypy.lib.encoding')
|
||||
|
||||
def missing_cElementTree(finder, caller):
|
||||
"""the cElementTree has been incorporated into the standard library in
|
||||
Python 2.5 so ignore its absence if it cannot found."""
|
||||
if sys.version_info[:2] >= (2, 5):
|
||||
caller.IgnoreName("cElementTree")
|
||||
|
||||
|
||||
def missing_EasyDialogs(finder, caller):
|
||||
"""the EasyDialogs module is not normally present on Windows but it also
|
||||
may be so instead of excluding it completely, ignore it if it can't be
|
||||
found"""
|
||||
if sys.platform == "win32":
|
||||
caller.IgnoreName("EasyDialogs")
|
||||
|
||||
|
||||
def missing_readline(finder, caller):
|
||||
"""the readline module is not normally present on Windows but it also may
|
||||
be so instead of excluding it completely, ignore it if it can't be
|
||||
found"""
|
||||
if sys.platform == "win32":
|
||||
caller.IgnoreName("readline")
|
||||
|
||||
|
||||
def missing_xml_etree(finder, caller):
|
||||
"""the xml.etree package is new for Python 2.5 but it is common practice
|
||||
to use a try..except.. block in order to support versions earlier than
|
||||
Python 2.5 transparently; ignore the absence of the package in this
|
||||
situation."""
|
||||
if sys.version_info[:2] < (2, 5):
|
||||
caller.IgnoreName("xml.etree")
|
||||
|
@ -1,171 +0,0 @@
|
||||
import optparse
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import sys
|
||||
|
||||
import cx_Freeze
|
||||
|
||||
__all__ = ["main"]
|
||||
|
||||
USAGE = \
|
||||
"""
|
||||
%prog [options] [SCRIPT]
|
||||
|
||||
Freeze a Python script and all of its referenced modules to a base
|
||||
executable which can then be distributed without requiring a Python
|
||||
installation."""
|
||||
|
||||
VERSION = \
|
||||
"""
|
||||
%%prog %s
|
||||
Copyright (c) 2007-2008 Colt Engineering. All rights reserved.
|
||||
Copyright (c) 2001-2006 Computronix Corporation. All rights reserved.""" % \
|
||||
cx_Freeze.version
|
||||
|
||||
|
||||
def ParseCommandLine():
|
||||
parser = optparse.OptionParser(version = VERSION.strip(),
|
||||
usage = USAGE.strip())
|
||||
parser.add_option("-O",
|
||||
action = "count",
|
||||
default = 0,
|
||||
dest = "optimized",
|
||||
help = "optimize generated bytecode as per PYTHONOPTIMIZE; "
|
||||
"use -OO in order to remove doc strings")
|
||||
parser.add_option("-c", "--compress",
|
||||
action = "store_true",
|
||||
dest = "compress",
|
||||
help = "compress byte code in zip files")
|
||||
parser.add_option("--base-name",
|
||||
dest = "baseName",
|
||||
metavar = "NAME",
|
||||
help = "file on which to base the target file; if the name of the "
|
||||
"file is not an absolute file name, the subdirectory bases "
|
||||
"(rooted in the directory in which the freezer is found) "
|
||||
"will be searched for a file matching the name")
|
||||
parser.add_option("--init-script",
|
||||
dest = "initScript",
|
||||
metavar = "NAME",
|
||||
help = "script which will be executed upon startup; if the name "
|
||||
"of the file is not an absolute file name, the "
|
||||
"subdirectory initscripts (rooted in the directory in "
|
||||
"which the cx_Freeze package is found) will be searched "
|
||||
"for a file matching the name")
|
||||
parser.add_option("--target-dir", "--install-dir",
|
||||
dest = "targetDir",
|
||||
metavar = "DIR",
|
||||
help = "the directory in which to place the target file and "
|
||||
"any dependent files")
|
||||
parser.add_option("--target-name",
|
||||
dest = "targetName",
|
||||
metavar = "NAME",
|
||||
help = "the name of the file to create instead of the base name "
|
||||
"of the script and the extension of the base binary")
|
||||
parser.add_option("--no-copy-deps",
|
||||
dest = "copyDeps",
|
||||
default = True,
|
||||
action = "store_false",
|
||||
help = "do not copy the dependent files (extensions, shared "
|
||||
"libraries, etc.) to the target directory; this also "
|
||||
"modifies the default init script to ConsoleKeepPath.py "
|
||||
"and means that the target executable requires a Python "
|
||||
"installation to execute properly")
|
||||
parser.add_option("--default-path",
|
||||
action = "append",
|
||||
dest = "defaultPath",
|
||||
metavar = "DIRS",
|
||||
help = "list of paths separated by the standard path separator "
|
||||
"for the platform which will be used to initialize "
|
||||
"sys.path prior to running the module finder")
|
||||
parser.add_option("--include-path",
|
||||
action = "append",
|
||||
dest = "includePath",
|
||||
metavar = "DIRS",
|
||||
help = "list of paths separated by the standard path separator "
|
||||
"for the platform which will be used to modify sys.path "
|
||||
"prior to running the module finder")
|
||||
parser.add_option("--replace-paths",
|
||||
dest = "replacePaths",
|
||||
metavar = "DIRECTIVES",
|
||||
help = "replace all the paths in modules found in the given paths "
|
||||
"with the given replacement string; multiple values are "
|
||||
"separated by the standard path separator and each value "
|
||||
"is of the form path=replacement_string; path can be * "
|
||||
"which means all paths not already specified")
|
||||
parser.add_option("--include-modules",
|
||||
dest = "includeModules",
|
||||
metavar = "NAMES",
|
||||
help = "comma separated list of modules to include")
|
||||
parser.add_option("--exclude-modules",
|
||||
dest = "excludeModules",
|
||||
metavar = "NAMES",
|
||||
help = "comma separated list of modules to exclude")
|
||||
parser.add_option("--ext-list-file",
|
||||
dest = "extListFile",
|
||||
metavar = "NAME",
|
||||
help = "name of file in which to place the list of dependent files "
|
||||
"which were copied into the target directory")
|
||||
parser.add_option("-z", "--zip-include",
|
||||
dest = "zipIncludes",
|
||||
action = "append",
|
||||
default = [],
|
||||
metavar = "SPEC",
|
||||
help = "name of file to add to the zip file or a specification of "
|
||||
"the form name=arcname which will specify the archive name "
|
||||
"to use; multiple --zip-include arguments can be used")
|
||||
options, args = parser.parse_args()
|
||||
if len(args) == 0:
|
||||
options.script = None
|
||||
elif len(args) == 1:
|
||||
options.script, = args
|
||||
else:
|
||||
parser.error("only one script can be specified")
|
||||
if not args and options.includeModules is None and options.copyDeps:
|
||||
parser.error("script or a list of modules must be specified")
|
||||
if not args and options.targetName is None:
|
||||
parser.error("script or a target name must be specified")
|
||||
if options.excludeModules:
|
||||
options.excludeModules = options.excludeModules.split(",")
|
||||
else:
|
||||
options.excludeModules = []
|
||||
if options.includeModules:
|
||||
options.includeModules = options.includeModules.split(",")
|
||||
else:
|
||||
options.includeModules = []
|
||||
replacePaths = []
|
||||
if options.replacePaths:
|
||||
for directive in options.replacePaths.split(os.pathsep):
|
||||
fromPath, replacement = directive.split("=")
|
||||
replacePaths.append((fromPath, replacement))
|
||||
options.replacePaths = replacePaths
|
||||
if options.defaultPath is not None:
|
||||
sys.path = [p for mp in options.defaultPath \
|
||||
for p in mp.split(os.pathsep)]
|
||||
if options.includePath is not None:
|
||||
paths = [p for mp in options.includePath for p in mp.split(os.pathsep)]
|
||||
sys.path = paths + sys.path
|
||||
if options.script is not None:
|
||||
sys.path.insert(0, os.path.dirname(options.script))
|
||||
return options
|
||||
|
||||
|
||||
def main():
|
||||
options = ParseCommandLine()
|
||||
executables = [cx_Freeze.Executable(options.script,
|
||||
targetName = options.targetName)]
|
||||
freezer = cx_Freeze.Freezer(executables,
|
||||
includes = options.includeModules,
|
||||
excludes = options.excludeModules,
|
||||
replacePaths = options.replacePaths,
|
||||
compress = options.compress,
|
||||
optimizeFlag = options.optimized,
|
||||
copyDependentFiles = options.copyDeps,
|
||||
initScript = options.initScript,
|
||||
base = options.baseName,
|
||||
path = None,
|
||||
createLibraryZip = False,
|
||||
appendScriptToExe = True,
|
||||
targetDir = options.targetDir)
|
||||
freezer.Freeze()
|
||||
|
@ -1,337 +0,0 @@
|
||||
import distutils.command.bdist_msi
|
||||
import msilib
|
||||
import os
|
||||
|
||||
__all__ = [ "bdist_msi" ]
|
||||
|
||||
# force the remove existing products action to happen first since Windows
|
||||
# installer appears to be braindead and doesn't handle files shared between
|
||||
# different "products" very well
|
||||
sequence = msilib.sequence.InstallExecuteSequence
|
||||
for index, info in enumerate(sequence):
|
||||
if info[0] == u'RemoveExistingProducts':
|
||||
sequence[index] = (info[0], info[1], 1450)
|
||||
|
||||
|
||||
class bdist_msi(distutils.command.bdist_msi.bdist_msi):
|
||||
user_options = distutils.command.bdist_msi.bdist_msi.user_options + [
|
||||
('add-to-path=', None, 'add target dir to PATH environment variable'),
|
||||
('upgrade-code=', None, 'upgrade code to use')
|
||||
]
|
||||
x = y = 50
|
||||
width = 370
|
||||
height = 300
|
||||
title = "[ProductName] Setup"
|
||||
modeless = 1
|
||||
modal = 3
|
||||
|
||||
def add_config(self, fullname):
|
||||
initialTargetDir = self.get_initial_target_dir(fullname)
|
||||
if self.add_to_path is None:
|
||||
self.add_to_path = False
|
||||
for executable in self.distribution.executables:
|
||||
if os.path.basename(executable.base).startswith("Console"):
|
||||
self.add_to_path = True
|
||||
break
|
||||
if self.add_to_path:
|
||||
msilib.add_data(self.db, 'Environment',
|
||||
[("E_PATH", "Path", r"[~];[TARGETDIR]", "TARGETDIR")])
|
||||
msilib.add_data(self.db, 'CustomAction',
|
||||
[("InitialTargetDir", 256 + 51, "TARGETDIR", initialTargetDir)
|
||||
])
|
||||
msilib.add_data(self.db, 'InstallExecuteSequence',
|
||||
[("InitialTargetDir", 'TARGETDIR=""', 401)])
|
||||
msilib.add_data(self.db, 'InstallUISequence',
|
||||
[("PrepareDlg", None, 140),
|
||||
("InitialTargetDir", 'TARGETDIR=""', 401),
|
||||
("SelectDirectoryDlg", "not Installed", 1230),
|
||||
("MaintenanceTypeDlg",
|
||||
"Installed and not Resume and not Preselected", 1250),
|
||||
("ProgressDlg", None, 1280)
|
||||
])
|
||||
|
||||
def add_cancel_dialog(self):
|
||||
dialog = msilib.Dialog(self.db, "CancelDlg", 50, 10, 260, 85, 3,
|
||||
self.title, "No", "No", "No")
|
||||
dialog.text("Text", 48, 15, 194, 30, 3,
|
||||
"Are you sure you want to cancel [ProductName] installation?")
|
||||
button = dialog.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No")
|
||||
button.event("EndDialog", "Exit")
|
||||
button = dialog.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes")
|
||||
button.event("EndDialog", "Return")
|
||||
|
||||
def add_error_dialog(self):
|
||||
dialog = msilib.Dialog(self.db, "ErrorDlg", 50, 10, 330, 101, 65543,
|
||||
self.title, "ErrorText", None, None)
|
||||
dialog.text("ErrorText", 50, 9, 280, 48, 3, "")
|
||||
for text, x in [("No", 120), ("Yes", 240), ("Abort", 0),
|
||||
("Cancel", 42), ("Ignore", 81), ("Ok", 159), ("Retry", 198)]:
|
||||
button = dialog.pushbutton(text[0], x, 72, 81, 21, 3, text, None)
|
||||
button.event("EndDialog", "Error%s" % text)
|
||||
|
||||
def add_exit_dialog(self):
|
||||
dialog = distutils.command.bdist_msi.PyDialog(self.db, "ExitDialog",
|
||||
self.x, self.y, self.width, self.height, self.modal,
|
||||
self.title, "Finish", "Finish", "Finish")
|
||||
dialog.title("Completing the [ProductName] installer")
|
||||
dialog.back("< Back", "Finish", active = False)
|
||||
dialog.cancel("Cancel", "Back", active = False)
|
||||
dialog.text("Description", 15, 235, 320, 20, 0x30003,
|
||||
"Click the Finish button to exit the installer.")
|
||||
button = dialog.next("Finish", "Cancel", name = "Finish")
|
||||
button.event("EndDialog", "Return")
|
||||
|
||||
def add_fatal_error_dialog(self):
|
||||
dialog = distutils.command.bdist_msi.PyDialog(self.db, "FatalError",
|
||||
self.x, self.y, self.width, self.height, self.modal,
|
||||
self.title, "Finish", "Finish", "Finish")
|
||||
dialog.title("[ProductName] installer ended prematurely")
|
||||
dialog.back("< Back", "Finish", active = False)
|
||||
dialog.cancel("Cancel", "Back", active = False)
|
||||
dialog.text("Description1", 15, 70, 320, 80, 0x30003,
|
||||
"[ProductName] setup ended prematurely because of an error. "
|
||||
"Your system has not been modified. To install this program "
|
||||
"at a later time, please run the installation again.")
|
||||
dialog.text("Description2", 15, 155, 320, 20, 0x30003,
|
||||
"Click the Finish button to exit the installer.")
|
||||
button = dialog.next("Finish", "Cancel", name = "Finish")
|
||||
button.event("EndDialog", "Exit")
|
||||
|
||||
def add_files_in_use_dialog(self):
|
||||
dialog = distutils.command.bdist_msi.PyDialog(self.db, "FilesInUse",
|
||||
self.x, self.y, self.width, self.height, 19, self.title,
|
||||
"Retry", "Retry", "Retry", bitmap = False)
|
||||
dialog.text("Title", 15, 6, 200, 15, 0x30003,
|
||||
r"{\DlgFontBold8}Files in Use")
|
||||
dialog.text("Description", 20, 23, 280, 20, 0x30003,
|
||||
"Some files that need to be updated are currently in use.")
|
||||
dialog.text("Text", 20, 55, 330, 50, 3,
|
||||
"The following applications are using files that need to be "
|
||||
"updated by this setup. Close these applications and then "
|
||||
"click Retry to continue the installation or Cancel to exit "
|
||||
"it.")
|
||||
dialog.control("List", "ListBox", 20, 107, 330, 130, 7,
|
||||
"FileInUseProcess", None, None, None)
|
||||
button = dialog.back("Exit", "Ignore", name = "Exit")
|
||||
button.event("EndDialog", "Exit")
|
||||
button = dialog.next("Ignore", "Retry", name = "Ignore")
|
||||
button.event("EndDialog", "Ignore")
|
||||
button = dialog.cancel("Retry", "Exit", name = "Retry")
|
||||
button.event("EndDialog", "Retry")
|
||||
|
||||
def add_maintenance_type_dialog(self):
|
||||
dialog = distutils.command.bdist_msi.PyDialog(self.db,
|
||||
"MaintenanceTypeDlg", self.x, self.y, self.width, self.height,
|
||||
self.modal, self.title, "Next", "Next", "Cancel")
|
||||
dialog.title("Welcome to the [ProductName] Setup Wizard")
|
||||
dialog.text("BodyText", 15, 63, 330, 42, 3,
|
||||
"Select whether you want to repair or remove [ProductName].")
|
||||
group = dialog.radiogroup("RepairRadioGroup", 15, 108, 330, 60, 3,
|
||||
"MaintenanceForm_Action", "", "Next")
|
||||
group.add("Repair", 0, 18, 300, 17, "&Repair [ProductName]")
|
||||
group.add("Remove", 0, 36, 300, 17, "Re&move [ProductName]")
|
||||
dialog.back("< Back", None, active = False)
|
||||
button = dialog.next("Finish", "Cancel")
|
||||
button.event("[REINSTALL]", "ALL",
|
||||
'MaintenanceForm_Action="Repair"', 5)
|
||||
button.event("[Progress1]", "Repairing",
|
||||
'MaintenanceForm_Action="Repair"', 6)
|
||||
button.event("[Progress2]", "repairs",
|
||||
'MaintenanceForm_Action="Repair"', 7)
|
||||
button.event("Reinstall", "ALL",
|
||||
'MaintenanceForm_Action="Repair"', 8)
|
||||
button.event("[REMOVE]", "ALL",
|
||||
'MaintenanceForm_Action="Remove"', 11)
|
||||
button.event("[Progress1]", "Removing",
|
||||
'MaintenanceForm_Action="Remove"', 12)
|
||||
button.event("[Progress2]", "removes",
|
||||
'MaintenanceForm_Action="Remove"', 13)
|
||||
button.event("Remove", "ALL",
|
||||
'MaintenanceForm_Action="Remove"', 14)
|
||||
button.event("EndDialog", "Return",
|
||||
'MaintenanceForm_Action<>"Change"', 20)
|
||||
button = dialog.cancel("Cancel", "RepairRadioGroup")
|
||||
button.event("SpawnDialog", "CancelDlg")
|
||||
|
||||
def add_prepare_dialog(self):
|
||||
dialog = distutils.command.bdist_msi.PyDialog(self.db, "PrepareDlg",
|
||||
self.x, self.y, self.width, self.height, self.modeless,
|
||||
self.title, "Cancel", "Cancel", "Cancel")
|
||||
dialog.text("Description", 15, 70, 320, 40, 0x30003,
|
||||
"Please wait while the installer prepares to guide you through"
|
||||
"the installation.")
|
||||
dialog.title("Welcome to the [ProductName] installer")
|
||||
text = dialog.text("ActionText", 15, 110, 320, 20, 0x30003,
|
||||
"Pondering...")
|
||||
text.mapping("ActionText", "Text")
|
||||
text = dialog.text("ActionData", 15, 135, 320, 30, 0x30003, None)
|
||||
text.mapping("ActionData", "Text")
|
||||
dialog.back("Back", None, active = False)
|
||||
dialog.next("Next", None, active = False)
|
||||
button = dialog.cancel("Cancel", None)
|
||||
button.event("SpawnDialog", "CancelDlg")
|
||||
|
||||
def add_progress_dialog(self):
|
||||
dialog = distutils.command.bdist_msi.PyDialog(self.db, "ProgressDlg",
|
||||
self.x, self.y, self.width, self.height, self.modeless,
|
||||
self.title, "Cancel", "Cancel", "Cancel", bitmap = False)
|
||||
dialog.text("Title", 20, 15, 200, 15, 0x30003,
|
||||
r"{\DlgFontBold8}[Progress1] [ProductName]")
|
||||
dialog.text("Text", 35, 65, 300, 30, 3,
|
||||
"Please wait while the installer [Progress2] [ProductName].")
|
||||
dialog.text("StatusLabel", 35, 100 ,35, 20, 3, "Status:")
|
||||
text = dialog.text("ActionText", 70, 100, self.width - 70, 20, 3,
|
||||
"Pondering...")
|
||||
text.mapping("ActionText", "Text")
|
||||
control = dialog.control("ProgressBar", "ProgressBar", 35, 120, 300,
|
||||
10, 65537, None, "Progress done", None, None)
|
||||
control.mapping("SetProgress", "Progress")
|
||||
dialog.back("< Back", "Next", active = False)
|
||||
dialog.next("Next >", "Cancel", active = False)
|
||||
button = dialog.cancel("Cancel", "Back")
|
||||
button.event("SpawnDialog", "CancelDlg")
|
||||
|
||||
def add_properties(self):
|
||||
metadata = self.distribution.metadata
|
||||
props = [
|
||||
('DistVersion', metadata.get_version()),
|
||||
('DefaultUIFont', 'DlgFont8'),
|
||||
('ErrorDialog', 'ErrorDlg'),
|
||||
('Progress1', 'Install'),
|
||||
('Progress2', 'installs'),
|
||||
('MaintenanceForm_Action', 'Repair')
|
||||
]
|
||||
email = metadata.author_email or metadata.maintainer_email
|
||||
if email:
|
||||
props.append(("ARPCONTACT", email))
|
||||
if metadata.url:
|
||||
props.append(("ARPURLINFOABOUT", metadata.url))
|
||||
if self.upgrade_code is not None:
|
||||
props.append(("UpgradeCode", self.upgrade_code))
|
||||
msilib.add_data(self.db, 'Property', props)
|
||||
|
||||
def add_select_directory_dialog(self):
|
||||
dialog = distutils.command.bdist_msi.PyDialog(self.db,
|
||||
"SelectDirectoryDlg", self.x, self.y, self.width, self.height,
|
||||
self.modal, self.title, "Next", "Next", "Cancel")
|
||||
dialog.title("Select destination directory")
|
||||
dialog.back("< Back", None, active = False)
|
||||
button = dialog.next("Next >", "Cancel")
|
||||
button.event("SetTargetPath", "TARGETDIR", ordering = 1)
|
||||
button.event("SpawnWaitDialog", "WaitForCostingDlg", ordering = 2)
|
||||
button.event("EndDialog", "Return", ordering = 3)
|
||||
button = dialog.cancel("Cancel", "DirectoryCombo")
|
||||
button.event("SpawnDialog", "CancelDlg")
|
||||
dialog.control("DirectoryCombo", "DirectoryCombo", 15, 70, 272, 80,
|
||||
393219, "TARGETDIR", None, "DirectoryList", None)
|
||||
dialog.control("DirectoryList", "DirectoryList", 15, 90, 308, 136, 3,
|
||||
"TARGETDIR", None, "PathEdit", None)
|
||||
dialog.control("PathEdit", "PathEdit", 15, 230, 306, 16, 3,
|
||||
"TARGETDIR", None, "Next", None)
|
||||
button = dialog.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None)
|
||||
button.event("DirectoryListUp", "0")
|
||||
button = dialog.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None)
|
||||
button.event("DirectoryListNew", "0")
|
||||
|
||||
def add_text_styles(self):
|
||||
msilib.add_data(self.db, 'TextStyle',
|
||||
[("DlgFont8", "Tahoma", 9, None, 0),
|
||||
("DlgFontBold8", "Tahoma", 8, None, 1),
|
||||
("VerdanaBold10", "Verdana", 10, None, 1),
|
||||
("VerdanaRed9", "Verdana", 9, 255, 0)
|
||||
])
|
||||
|
||||
def add_ui(self):
|
||||
self.add_text_styles()
|
||||
self.add_error_dialog()
|
||||
self.add_fatal_error_dialog()
|
||||
self.add_cancel_dialog()
|
||||
self.add_exit_dialog()
|
||||
self.add_user_exit_dialog()
|
||||
self.add_files_in_use_dialog()
|
||||
self.add_wait_for_costing_dialog()
|
||||
self.add_prepare_dialog()
|
||||
self.add_select_directory_dialog()
|
||||
self.add_progress_dialog()
|
||||
self.add_maintenance_type_dialog()
|
||||
|
||||
def add_upgrade_config(self, sversion):
|
||||
if self.upgrade_code is not None:
|
||||
msilib.add_data(self.db, 'Upgrade',
|
||||
[(self.upgrade_code, None, sversion, None, 513, None,
|
||||
"REMOVEOLDVERSION"),
|
||||
(self.upgrade_code, sversion, None, None, 257, None,
|
||||
"REMOVENEWVERSION")
|
||||
])
|
||||
|
||||
def add_user_exit_dialog(self):
|
||||
dialog = distutils.command.bdist_msi.PyDialog(self.db, "UserExit",
|
||||
self.x, self.y, self.width, self.height, self.modal,
|
||||
self.title, "Finish", "Finish", "Finish")
|
||||
dialog.title("[ProductName] installer was interrupted")
|
||||
dialog.back("< Back", "Finish", active = False)
|
||||
dialog.cancel("Cancel", "Back", active = False)
|
||||
dialog.text("Description1", 15, 70, 320, 80, 0x30003,
|
||||
"[ProductName] setup was interrupted. Your system has not "
|
||||
"been modified. To install this program at a later time, "
|
||||
"please run the installation again.")
|
||||
dialog.text("Description2", 15, 155, 320, 20, 0x30003,
|
||||
"Click the Finish button to exit the installer.")
|
||||
button = dialog.next("Finish", "Cancel", name = "Finish")
|
||||
button.event("EndDialog", "Exit")
|
||||
|
||||
def add_wait_for_costing_dialog(self):
|
||||
dialog = msilib.Dialog(self.db, "WaitForCostingDlg", 50, 10, 260, 85,
|
||||
self.modal, self.title, "Return", "Return", "Return")
|
||||
dialog.text("Text", 48, 15, 194, 30, 3,
|
||||
"Please wait while the installer finishes determining your "
|
||||
"disk space requirements.")
|
||||
button = dialog.pushbutton("Return", 102, 57, 56, 17, 3, "Return",
|
||||
None)
|
||||
button.event("EndDialog", "Exit")
|
||||
|
||||
def get_initial_target_dir(self, fullname):
|
||||
return r"[ProgramFilesFolder]\%s" % fullname
|
||||
|
||||
def get_installer_filename(self, fullname):
|
||||
return os.path.join(self.dist_dir, "%s.msi" % fullname)
|
||||
|
||||
def initialize_options(self):
|
||||
distutils.command.bdist_msi.bdist_msi.initialize_options(self)
|
||||
self.upgrade_code = None
|
||||
self.add_to_path = None
|
||||
|
||||
def run(self):
|
||||
if not self.skip_build:
|
||||
self.run_command('build')
|
||||
install = self.reinitialize_command('install', reinit_subcommands = 1)
|
||||
install.prefix = self.bdist_dir
|
||||
install.skip_build = self.skip_build
|
||||
install.warn_dir = 0
|
||||
distutils.log.info("installing to %s", self.bdist_dir)
|
||||
install.ensure_finalized()
|
||||
install.run()
|
||||
self.mkpath(self.dist_dir)
|
||||
fullname = self.distribution.get_fullname()
|
||||
filename = os.path.abspath(self.get_installer_filename(fullname))
|
||||
if os.path.exists(filename):
|
||||
os.unlink(filename)
|
||||
metadata = self.distribution.metadata
|
||||
author = metadata.author or metadata.maintainer or "UNKNOWN"
|
||||
version = metadata.get_version()
|
||||
sversion = "%d.%d.%d" % \
|
||||
distutils.version.StrictVersion(version).version
|
||||
self.db = msilib.init_database(filename, msilib.schema,
|
||||
self.distribution.metadata.name, msilib.gen_uuid(), sversion,
|
||||
author)
|
||||
msilib.add_tables(self.db, msilib.sequence)
|
||||
self.add_properties()
|
||||
self.add_config(fullname)
|
||||
self.add_upgrade_config(sversion)
|
||||
self.add_ui()
|
||||
self.add_files()
|
||||
self.db.Commit()
|
||||
if not self.keep_temp:
|
||||
distutils.dir_util.remove_tree(self.bdist_dir,
|
||||
dry_run = self.dry_run)
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from cx_Freeze import main
|
||||
|
||||
main()
|
||||
|
@ -1,35 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# Console.py
|
||||
# Initialization script for cx_Freeze which manipulates the path so that the
|
||||
# directory in which the executable is found is searched for extensions but
|
||||
# no other directory is searched. It also sets the attribute sys.frozen so that
|
||||
# the Win32 extensions behave as expected.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import encodings
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
import zipimport
|
||||
|
||||
sys.frozen = True
|
||||
sys.path = sys.path[:4]
|
||||
|
||||
os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
|
||||
os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")
|
||||
|
||||
m = __import__("__main__")
|
||||
importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
|
||||
if INITSCRIPT_ZIP_FILE_NAME != SHARED_ZIP_FILE_NAME:
|
||||
moduleName = m.__name__
|
||||
else:
|
||||
name, ext = os.path.splitext(os.path.basename(os.path.normcase(FILE_NAME)))
|
||||
moduleName = "%s__main__" % name
|
||||
code = importer.get_code(moduleName)
|
||||
exec code in m.__dict__
|
||||
|
||||
if sys.version_info[:2] >= (2, 5):
|
||||
module = sys.modules.get("threading")
|
||||
if module is not None:
|
||||
module._shutdown()
|
||||
|
@ -1,19 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# ConsoleKeepPath.py
|
||||
# Initialization script for cx_Freeze which leaves the path alone and does
|
||||
# not set the sys.frozen attribute.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import sys
|
||||
import zipimport
|
||||
|
||||
m = __import__("__main__")
|
||||
importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
|
||||
code = importer.get_code(m.__name__)
|
||||
exec code in m.__dict__
|
||||
|
||||
if sys.version_info[:2] >= (2, 5):
|
||||
module = sys.modules.get("threading")
|
||||
if module is not None:
|
||||
module._shutdown()
|
||||
|
@ -1,38 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# ConsoleSetLibPath.py
|
||||
# Initialization script for cx_Freeze which manipulates the path so that the
|
||||
# directory in which the executable is found is searched for extensions but
|
||||
# no other directory is searched. The environment variable LD_LIBRARY_PATH is
|
||||
# manipulated first, however, to ensure that shared libraries found in the
|
||||
# target directory are found. This requires a restart of the executable because
|
||||
# the environment variable LD_LIBRARY_PATH is only checked at startup.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import encodings
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
import zipimport
|
||||
|
||||
paths = os.environ.get("LD_LIBRARY_PATH", "").split(os.pathsep)
|
||||
if DIR_NAME not in paths:
|
||||
paths.insert(0, DIR_NAME)
|
||||
os.environ["LD_LIBRARY_PATH"] = os.pathsep.join(paths)
|
||||
os.execv(sys.executable, sys.argv)
|
||||
|
||||
sys.frozen = True
|
||||
sys.path = sys.path[:4]
|
||||
|
||||
os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
|
||||
os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")
|
||||
|
||||
m = __import__("__main__")
|
||||
importer = zipimport.zipimporter(INITSCRIPT_ZIP_FILE_NAME)
|
||||
code = importer.get_code(m.__name__)
|
||||
exec code in m.__dict__
|
||||
|
||||
if sys.version_info[:2] >= (2, 5):
|
||||
module = sys.modules.get("threading")
|
||||
if module is not None:
|
||||
module._shutdown()
|
||||
|
@ -1,20 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# SharedLib.py
|
||||
# Initialization script for cx_Freeze which behaves similarly to the one for
|
||||
# console based applications but must handle the case where Python has already
|
||||
# been initialized and another DLL of this kind has been loaded. As such it
|
||||
# does not block the path unless sys.frozen is not already set.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import encodings
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
if not hasattr(sys, "frozen"):
|
||||
sys.frozen = True
|
||||
sys.path = sys.path[:4]
|
||||
|
||||
os.environ["TCL_LIBRARY"] = os.path.join(DIR_NAME, "tcl")
|
||||
os.environ["TK_LIBRARY"] = os.path.join(DIR_NAME, "tk")
|
||||
|
@ -1,23 +0,0 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# SharedLibSource.py
|
||||
# Initialization script for cx_Freeze which imports the site module (as per
|
||||
# normal processing of a Python script) and then searches for a file with the
|
||||
# same name as the shared library but with the extension .pth. The entries in
|
||||
# this file are used to modify the path to use for subsequent imports.
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
# the site module must be imported for normal behavior to take place; it is
|
||||
# done dynamically so that cx_Freeze will not add all modules referenced by
|
||||
# the site module to the frozen executable
|
||||
__import__("site")
|
||||
|
||||
# now locate the pth file to modify the path appropriately
|
||||
baseName, ext = os.path.splitext(FILE_NAME)
|
||||
pathFileName = baseName + ".pth"
|
||||
sys.path = [s.strip() for s in file(pathFileName).read().splitlines()] + \
|
||||
sys.path
|
||||
|
@ -1,7 +0,0 @@
|
||||
import sys
|
||||
|
||||
print "Hello from cx_Freeze Advanced #1"
|
||||
print
|
||||
|
||||
module = __import__("testfreeze_1")
|
||||
|
@ -1,7 +0,0 @@
|
||||
import sys
|
||||
|
||||
print "Hello from cx_Freeze Advanced #2"
|
||||
print
|
||||
|
||||
module = __import__("testfreeze_2")
|
||||
|
@ -1 +0,0 @@
|
||||
print "Test freeze module #1"
|
@ -1 +0,0 @@
|
||||
print "Test freeze module #2"
|
@ -1,31 +0,0 @@
|
||||
# An advanced setup script to create multiple executables and demonstrate a few
|
||||
# of the features available to setup scripts
|
||||
#
|
||||
# hello.py is a very simple "Hello, world" type script which also displays the
|
||||
# environment in which the script runs
|
||||
#
|
||||
# Run the build process by running the command 'python setup.py build'
|
||||
#
|
||||
# If everything works well you should find a subdirectory in the build
|
||||
# subdirectory that contains the files needed to run the script without Python
|
||||
|
||||
import sys
|
||||
from cx_Freeze import setup, Executable
|
||||
|
||||
executables = [
|
||||
Executable("advanced_1.py"),
|
||||
Executable("advanced_2.py")
|
||||
]
|
||||
|
||||
buildOptions = dict(
|
||||
compressed = True,
|
||||
includes = ["testfreeze_1", "testfreeze_2"],
|
||||
path = sys.path + ["modules"])
|
||||
|
||||
setup(
|
||||
name = "advanced_cx_Freeze_sample",
|
||||
version = "0.1",
|
||||
description = "Advanced sample cx_Freeze script",
|
||||
options = dict(build_exe = buildOptions),
|
||||
executables = executables)
|
||||
|
@ -1,27 +0,0 @@
|
||||
# A simple setup script to create an executable using matplotlib.
|
||||
#
|
||||
# test_matplotlib.py is a very simple matplotlib application that demonstrates
|
||||
# its use.
|
||||
#
|
||||
# Run the build process by running the command 'python setup.py build'
|
||||
#
|
||||
# If everything works well you should find a subdirectory in the build
|
||||
# subdirectory that contains the files needed to run the application
|
||||
|
||||
import cx_Freeze
|
||||
import sys
|
||||
|
||||
base = None
|
||||
if sys.platform == "win32":
|
||||
base = "Win32GUI"
|
||||
|
||||
executables = [
|
||||
cx_Freeze.Executable("test_matplotlib.py", base = base)
|
||||
]
|
||||
|
||||
cx_Freeze.setup(
|
||||
name = "test_matplotlib",
|
||||
version = "0.1",
|
||||
description = "Sample matplotlib script",
|
||||
executables = executables)
|
||||
|
@ -1,48 +0,0 @@
|
||||
from numpy import arange, sin, pi
|
||||
import matplotlib
|
||||
matplotlib.use('WXAgg')
|
||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
|
||||
from matplotlib.figure import Figure
|
||||
from wx import *
|
||||
|
||||
class CanvasFrame(Frame):
|
||||
def __init__(self):
|
||||
Frame.__init__(self,None,-1, 'CanvasFrame',size=(550,350))
|
||||
self.SetBackgroundColour(NamedColor("WHITE"))
|
||||
self.figure = Figure()
|
||||
self.axes = self.figure.add_subplot(111)
|
||||
t = arange(0.0,3.0,0.01)
|
||||
s = sin(2*pi*t)
|
||||
self.axes.plot(t,s)
|
||||
self.canvas = FigureCanvas(self, -1, self.figure)
|
||||
self.sizer = BoxSizer(VERTICAL)
|
||||
self.sizer.Add(self.canvas, 1, LEFT | TOP | GROW)
|
||||
self.SetSizerAndFit(self.sizer)
|
||||
self.add_toolbar()
|
||||
|
||||
def add_toolbar(self):
|
||||
self.toolbar = NavigationToolbar2Wx(self.canvas)
|
||||
self.toolbar.Realize()
|
||||
if Platform == '__WXMAC__':
|
||||
self.SetToolBar(self.toolbar)
|
||||
else:
|
||||
tw, th = self.toolbar.GetSizeTuple()
|
||||
fw, fh = self.canvas.GetSizeTuple()
|
||||
self.toolbar.SetSize(Size(fw, th))
|
||||
self.sizer.Add(self.toolbar, 0, LEFT | EXPAND)
|
||||
self.toolbar.update()
|
||||
|
||||
def OnPaint(self, event):
|
||||
self.canvas.draw()
|
||||
|
||||
class App(App):
|
||||
def OnInit(self):
|
||||
'Create the main window and insert the custom frame'
|
||||
frame = CanvasFrame()
|
||||
frame.Show(True)
|
||||
return True
|
||||
|
||||
app = App(0)
|
||||
app.MainLoop()
|
||||
|
@ -1,3 +0,0 @@
|
||||
print "importing pkg1"
|
||||
from . import sub1
|
||||
from . import pkg2
|
@ -1,3 +0,0 @@
|
||||
print "importing pkg1.pkg2"
|
||||
from . import sub3
|
||||
from .. import sub4
|
@ -1,3 +0,0 @@
|
||||
print "importing pkg1.pkg2.sub3"
|
||||
from . import sub5
|
||||
from .. import sub6
|
@ -1 +0,0 @@
|
||||
print "importing pkg1.pkg2.sub5"
|
@ -1,2 +0,0 @@
|
||||
print "importing pkg1.sub1"
|
||||
from . import sub2
|
@ -1 +0,0 @@
|
||||
print "importing pkg1.sub2"
|
@ -1 +0,0 @@
|
||||
print 'importing pkg1.sub4'
|
@ -1 +0,0 @@
|
||||
print "importing pkg1.sub6"
|
@ -1 +0,0 @@
|
||||
import pkg1
|
@ -1,16 +0,0 @@
|
||||
# relimport.py is a very simple script that tests importing using relative
|
||||
# imports (available in Python 2.5 and up)
|
||||
#
|
||||
# Run the build process by running the command 'python setup.py build'
|
||||
#
|
||||
# If everything works well you should find a subdirectory in the build
|
||||
# subdirectory that contains the files needed to run the script without Python
|
||||
|
||||
from cx_Freeze import setup, Executable
|
||||
|
||||
setup(
|
||||
name = "relimport",
|
||||
version = "0.1",
|
||||
description = "Sample cx_Freeze script for relative imports",
|
||||
executables = [Executable("relimport.py")])
|
||||
|
@ -1,19 +0,0 @@
|
||||
import sys
|
||||
|
||||
print "Hello from cx_Freeze"
|
||||
print
|
||||
|
||||
print "sys.executable", sys.executable
|
||||
print "sys.prefix", sys.prefix
|
||||
print
|
||||
|
||||
print "ARGUMENTS:"
|
||||
for a in sys.argv:
|
||||
print a
|
||||
print
|
||||
|
||||
print "PATH:"
|
||||
for p in sys.path:
|
||||
print p
|
||||
print
|
||||
|
@ -1,18 +0,0 @@
|
||||
# A very simple setup script to create a single executable
|
||||
#
|
||||
# hello.py is a very simple "Hello, world" type script which also displays the
|
||||
# environment in which the script runs
|
||||
#
|
||||
# Run the build process by running the command 'python setup.py build'
|
||||
#
|
||||
# If everything works well you should find a subdirectory in the build
|
||||
# subdirectory that contains the files needed to run the script without Python
|
||||
|
||||
from cx_Freeze import setup, Executable
|
||||
|
||||
setup(
|
||||
name = "hello",
|
||||
version = "0.1",
|
||||
description = "Sample cx_Freeze script",
|
||||
executables = [Executable("hello.py")])
|
||||
|
@ -1,25 +0,0 @@
|
||||
# A simple setup script to create an executable running wxPython. This also
|
||||
# demonstrates the method for creating a Windows executable that does not have
|
||||
# an associated console.
|
||||
#
|
||||
# wxapp.py is a very simple "Hello, world" type wxPython application
|
||||
#
|
||||
# Run the build process by running the command 'python setup.py build'
|
||||
#
|
||||
# If everything works well you should find a subdirectory in the build
|
||||
# subdirectory that contains the files needed to run the application
|
||||
|
||||
import sys
|
||||
|
||||
from cx_Freeze import setup, Executable
|
||||
|
||||
base = None
|
||||
if sys.platform == "win32":
|
||||
base = "Win32GUI"
|
||||
|
||||
setup(
|
||||
name = "hello",
|
||||
version = "0.1",
|
||||
description = "Sample cx_Freeze wxPython script",
|
||||
executables = [Executable("wxapp.py", base = base)])
|
||||
|
@ -1,42 +0,0 @@
|
||||
import wx
|
||||
|
||||
class Frame(wx.Frame):
|
||||
|
||||
def __init__(self):
|
||||
wx.Frame.__init__(self, parent = None, title = "Hello from cx_Freeze")
|
||||
panel = wx.Panel(self)
|
||||
closeMeButton = wx.Button(panel, -1, "Close Me")
|
||||
wx.EVT_BUTTON(self, closeMeButton.GetId(), self.OnCloseMe)
|
||||
wx.EVT_CLOSE(self, self.OnCloseWindow)
|
||||
pushMeButton = wx.Button(panel, -1, "Push Me")
|
||||
wx.EVT_BUTTON(self, pushMeButton.GetId(), self.OnPushMe)
|
||||
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
sizer.Add(closeMeButton, flag = wx.ALL, border = 20)
|
||||
sizer.Add(pushMeButton, flag = wx.ALL, border = 20)
|
||||
panel.SetSizer(sizer)
|
||||
topSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
topSizer.Add(panel, flag = wx.ALL | wx.EXPAND)
|
||||
topSizer.Fit(self)
|
||||
|
||||
def OnCloseMe(self, event):
|
||||
self.Close(True)
|
||||
|
||||
def OnPushMe(self, event):
|
||||
1 / 0
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
|
||||
class App(wx.App):
|
||||
|
||||
def OnInit(self):
|
||||
frame = Frame()
|
||||
frame.Show(True)
|
||||
self.SetTopWindow(frame)
|
||||
return True
|
||||
|
||||
|
||||
app = App(1)
|
||||
app.MainLoop()
|
||||
|
@ -1,197 +0,0 @@
|
||||
"""
|
||||
Distutils script for cx_Freeze.
|
||||
"""
|
||||
|
||||
import distutils.command.bdist_rpm
|
||||
import distutils.command.build_ext
|
||||
import distutils.command.build_scripts
|
||||
import distutils.command.install
|
||||
import distutils.command.install_data
|
||||
import distutils.sysconfig
|
||||
import os
|
||||
import sys
|
||||
|
||||
from distutils.core import setup
|
||||
from distutils.extension import Extension
|
||||
|
||||
class bdist_rpm(distutils.command.bdist_rpm.bdist_rpm):
|
||||
|
||||
# rpm automatically byte compiles all Python files in a package but we
|
||||
# don't want that to happen for initscripts and samples so we tell it to
|
||||
# ignore those files
|
||||
def _make_spec_file(self):
|
||||
specFile = distutils.command.bdist_rpm.bdist_rpm._make_spec_file(self)
|
||||
specFile.insert(0, "%define _unpackaged_files_terminate_build 0%{nil}")
|
||||
return specFile
|
||||
|
||||
def run(self):
|
||||
distutils.command.bdist_rpm.bdist_rpm.run(self)
|
||||
specFile = os.path.join(self.rpm_base, "SPECS",
|
||||
"%s.spec" % self.distribution.get_name())
|
||||
queryFormat = "%{name}-%{version}-%{release}.%{arch}.rpm"
|
||||
command = "rpm -q --qf '%s' --specfile %s" % (queryFormat, specFile)
|
||||
origFileName = os.popen(command).read()
|
||||
parts = origFileName.split("-")
|
||||
parts.insert(2, "py%s%s" % sys.version_info[:2])
|
||||
newFileName = "-".join(parts)
|
||||
self.move_file(os.path.join("dist", origFileName),
|
||||
os.path.join("dist", newFileName))
|
||||
|
||||
|
||||
class build_ext(distutils.command.build_ext.build_ext):
|
||||
|
||||
def build_extension(self, ext):
|
||||
if ext.name.find("bases") < 0:
|
||||
distutils.command.build_ext.build_ext.build_extension(self, ext)
|
||||
return
|
||||
os.environ["LD_RUN_PATH"] = "${ORIGIN}:${ORIGIN}/../lib"
|
||||
objects = self.compiler.compile(ext.sources,
|
||||
output_dir = self.build_temp,
|
||||
include_dirs = ext.include_dirs,
|
||||
debug = self.debug,
|
||||
depends = ext.depends)
|
||||
fileName = os.path.splitext(self.get_ext_filename(ext.name))[0]
|
||||
fullName = os.path.join(self.build_lib, fileName)
|
||||
libraryDirs = ext.library_dirs or []
|
||||
libraries = self.get_libraries(ext)
|
||||
extraArgs = ext.extra_link_args or []
|
||||
if sys.platform != "win32":
|
||||
vars = distutils.sysconfig.get_config_vars()
|
||||
libraryDirs.append(vars["LIBPL"])
|
||||
libraries.append("python%s.%s" % sys.version_info[:2])
|
||||
if vars["LINKFORSHARED"]:
|
||||
extraArgs.extend(vars["LINKFORSHARED"].split())
|
||||
if vars["LIBS"]:
|
||||
extraArgs.extend(vars["LIBS"].split())
|
||||
if vars["LIBM"]:
|
||||
extraArgs.append(vars["LIBM"])
|
||||
if vars["BASEMODLIBS"]:
|
||||
extraArgs.extend(vars["BASEMODLIBS"].split())
|
||||
if vars["LOCALMODLIBS"]:
|
||||
extraArgs.extend(vars["LOCALMODLIBS"].split())
|
||||
extraArgs.append("-s")
|
||||
self.compiler.link_executable(objects, fullName,
|
||||
libraries = libraries,
|
||||
library_dirs = libraryDirs,
|
||||
runtime_library_dirs = ext.runtime_library_dirs,
|
||||
extra_postargs = extraArgs,
|
||||
debug = self.debug)
|
||||
|
||||
def get_ext_filename(self, name):
|
||||
fileName = distutils.command.build_ext.build_ext.get_ext_filename(self,
|
||||
name)
|
||||
if name.find("bases") < 0:
|
||||
return fileName
|
||||
ext = self.compiler.exe_extension or ""
|
||||
return os.path.splitext(fileName)[0] + ext
|
||||
|
||||
|
||||
class build_scripts(distutils.command.build_scripts.build_scripts):
|
||||
|
||||
def copy_scripts(self):
|
||||
distutils.command.build_scripts.build_scripts.copy_scripts(self)
|
||||
if sys.platform == "win32":
|
||||
for script in self.scripts:
|
||||
batFileName = os.path.join(self.build_dir, script + ".bat")
|
||||
fullScriptName = r"%s\Scripts\%s" % \
|
||||
(os.path.dirname(sys.executable), script)
|
||||
command = "%s %s %%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9" % \
|
||||
(sys.executable, fullScriptName)
|
||||
file(batFileName, "w").write("@echo off\n\n%s" % command)
|
||||
|
||||
|
||||
class install(distutils.command.install.install):
|
||||
|
||||
def get_sub_commands(self):
|
||||
subCommands = distutils.command.install.install.get_sub_commands(self)
|
||||
subCommands.append("install_packagedata")
|
||||
return subCommands
|
||||
|
||||
|
||||
class install_packagedata(distutils.command.install_data.install_data):
|
||||
|
||||
def run(self):
|
||||
installCommand = self.get_finalized_command("install")
|
||||
installDir = getattr(installCommand, "install_lib")
|
||||
sourceDirs = ["samples", "initscripts"]
|
||||
while sourceDirs:
|
||||
sourceDir = sourceDirs.pop(0)
|
||||
targetDir = os.path.join(installDir, "cx_Freeze", sourceDir)
|
||||
self.mkpath(targetDir)
|
||||
for name in os.listdir(sourceDir):
|
||||
if name == "build" or name.startswith("."):
|
||||
continue
|
||||
fullSourceName = os.path.join(sourceDir, name)
|
||||
if os.path.isdir(fullSourceName):
|
||||
sourceDirs.append(fullSourceName)
|
||||
else:
|
||||
fullTargetName = os.path.join(targetDir, name)
|
||||
self.copy_file(fullSourceName, fullTargetName)
|
||||
self.outfiles.append(fullTargetName)
|
||||
|
||||
|
||||
commandClasses = dict(
|
||||
build_ext = build_ext,
|
||||
build_scripts = build_scripts,
|
||||
bdist_rpm = bdist_rpm,
|
||||
install = install,
|
||||
install_packagedata = install_packagedata)
|
||||
|
||||
if sys.platform == "win32":
|
||||
libraries = ["imagehlp"]
|
||||
else:
|
||||
libraries = []
|
||||
utilModule = Extension("cx_Freeze.util", ["source/util.c"],
|
||||
libraries = libraries)
|
||||
depends = ["source/bases/Common.c"]
|
||||
if sys.platform == "win32":
|
||||
if sys.version_info[:2] >= (2, 6):
|
||||
extraSources = ["source/bases/manifest.rc"]
|
||||
else:
|
||||
extraSources = ["source/bases/dummy.rc"]
|
||||
else:
|
||||
extraSources = []
|
||||
console = Extension("cx_Freeze.bases.Console",
|
||||
["source/bases/Console.c"] + extraSources, depends = depends)
|
||||
consoleKeepPath = Extension("cx_Freeze.bases.ConsoleKeepPath",
|
||||
["source/bases/ConsoleKeepPath.c"] + extraSources, depends = depends)
|
||||
extensions = [utilModule, console, consoleKeepPath]
|
||||
if sys.platform == "win32":
|
||||
gui = Extension("cx_Freeze.bases.Win32GUI",
|
||||
["source/bases/Win32GUI.c"] + extraSources,
|
||||
depends = depends, extra_link_args = ["-mwindows"])
|
||||
extensions.append(gui)
|
||||
|
||||
docFiles = "LICENSE.txt README.txt HISTORY.txt doc/cx_Freeze.html"
|
||||
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: Python Software Foundation License",
|
||||
"Natural Language :: English",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: C",
|
||||
"Programming Language :: Python",
|
||||
"Topic :: Software Development :: Build Tools",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: System :: Software Distribution",
|
||||
"Topic :: Utilities"
|
||||
]
|
||||
|
||||
setup(name = "cx_Freeze",
|
||||
description = "create standalone executables from Python scripts",
|
||||
long_description = "create standalone executables from Python scripts",
|
||||
version = "4.0.1",
|
||||
cmdclass = commandClasses,
|
||||
options = dict(bdist_rpm = dict(doc_files = docFiles),
|
||||
install = dict(optimize = 1)),
|
||||
ext_modules = extensions,
|
||||
packages = ['cx_Freeze'],
|
||||
maintainer="Anthony Tuininga",
|
||||
maintainer_email="anthony.tuininga@gmail.com",
|
||||
url = "http://cx-freeze.sourceforge.net",
|
||||
scripts = ["cxfreeze"],
|
||||
classifiers = classifiers,
|
||||
keywords = "freeze",
|
||||
license = "Python Software Foundation License")
|
||||
|
@ -1,262 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Common.c
|
||||
// Routines which are common to running frozen executables.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <compile.h>
|
||||
#include <eval.h>
|
||||
#include <osdefs.h>
|
||||
|
||||
// global variables (used for simplicity)
|
||||
static PyObject *g_FileName = NULL;
|
||||
static PyObject *g_DirName = NULL;
|
||||
static PyObject *g_ExclusiveZipFileName = NULL;
|
||||
static PyObject *g_SharedZipFileName = NULL;
|
||||
static PyObject *g_InitScriptZipFileName = NULL;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GetDirName()
|
||||
// Return the directory name of the given path.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int GetDirName(
|
||||
const char *path, // path to calculate dir name for
|
||||
PyObject **dirName) // directory name (OUT)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = strlen(path); i > 0 && path[i] != SEP; --i);
|
||||
*dirName = PyString_FromStringAndSize(path, i);
|
||||
if (!*dirName)
|
||||
return FatalError("cannot create string for directory name");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SetExecutableName()
|
||||
// Set the script to execute and calculate the directory in which the
|
||||
// executable is found as well as the exclusive (only for this executable) and
|
||||
// shared zip file names.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int SetExecutableName(
|
||||
const char *fileName) // script to execute
|
||||
{
|
||||
char temp[MAXPATHLEN + 12], *ptr;
|
||||
#ifndef WIN32
|
||||
char linkData[MAXPATHLEN + 1];
|
||||
struct stat statData;
|
||||
size_t linkSize, i;
|
||||
PyObject *dirName;
|
||||
#endif
|
||||
|
||||
// store file name
|
||||
g_FileName = PyString_FromString(fileName);
|
||||
if (!g_FileName)
|
||||
return FatalError("cannot create string for file name");
|
||||
|
||||
#ifndef WIN32
|
||||
for (i = 0; i < 25; i++) {
|
||||
if (lstat(fileName, &statData) < 0) {
|
||||
PyErr_SetFromErrnoWithFilename(PyExc_OSError, (char*) fileName);
|
||||
return FatalError("unable to stat file");
|
||||
}
|
||||
if (!S_ISLNK(statData.st_mode))
|
||||
break;
|
||||
linkSize = readlink(fileName, linkData, sizeof(linkData));
|
||||
if (linkSize < 0) {
|
||||
PyErr_SetFromErrnoWithFilename(PyExc_OSError, (char*) fileName);
|
||||
return FatalError("unable to stat file");
|
||||
}
|
||||
if (linkData[0] == '/') {
|
||||
Py_DECREF(g_FileName);
|
||||
g_FileName = PyString_FromStringAndSize(linkData, linkSize);
|
||||
} else {
|
||||
if (GetDirName(PyString_AS_STRING(g_FileName), &dirName) < 0)
|
||||
return -1;
|
||||
if (PyString_GET_SIZE(dirName) + linkSize + 1 > MAXPATHLEN) {
|
||||
Py_DECREF(dirName);
|
||||
return FatalError("cannot dereference link, path too large");
|
||||
}
|
||||
strcpy(temp, PyString_AS_STRING(dirName));
|
||||
strcat(temp, "/");
|
||||
strcat(temp, linkData);
|
||||
Py_DECREF(g_FileName);
|
||||
g_FileName = PyString_FromString(temp);
|
||||
}
|
||||
if (!g_FileName)
|
||||
return FatalError("cannot create string for linked file name");
|
||||
fileName = PyString_AS_STRING(g_FileName);
|
||||
}
|
||||
#endif
|
||||
|
||||
// calculate and store directory name
|
||||
if (GetDirName(fileName, &g_DirName) < 0)
|
||||
return -1;
|
||||
|
||||
// calculate and store exclusive zip file name
|
||||
strcpy(temp, fileName);
|
||||
ptr = temp + strlen(temp) - 1;
|
||||
while (ptr > temp && *ptr != SEP && *ptr != '.')
|
||||
ptr--;
|
||||
if (*ptr == '.')
|
||||
*ptr = '\0';
|
||||
strcat(temp, ".zip");
|
||||
g_ExclusiveZipFileName = PyString_FromString(temp);
|
||||
if (!g_ExclusiveZipFileName)
|
||||
return FatalError("cannot create string for exclusive zip file name");
|
||||
|
||||
// calculate and store shared zip file name
|
||||
strcpy(temp, PyString_AS_STRING(g_DirName));
|
||||
ptr = temp + strlen(temp);
|
||||
*ptr++ = SEP;
|
||||
strcpy(ptr, "library.zip");
|
||||
g_SharedZipFileName = PyString_FromString(temp);
|
||||
if (!g_SharedZipFileName)
|
||||
return FatalError("cannot create string for shared zip file name");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SetPathToSearch()
|
||||
// Set the path to search. This includes the file (for those situations where
|
||||
// a zip file is attached to the executable itself), the directory where the
|
||||
// executable is found (to search for extensions), the exclusive zip file
|
||||
// name and the shared zip file name.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int SetPathToSearch(void)
|
||||
{
|
||||
PyObject *pathList;
|
||||
|
||||
pathList = PySys_GetObject("path");
|
||||
if (!pathList)
|
||||
return FatalError("cannot acquire sys.path");
|
||||
if (PyList_Insert(pathList, 0, g_FileName) < 0)
|
||||
return FatalError("cannot insert file name into sys.path");
|
||||
if (PyList_Insert(pathList, 1, g_DirName) < 0)
|
||||
return FatalError("cannot insert directory name into sys.path");
|
||||
if (PyList_Insert(pathList, 2, g_ExclusiveZipFileName) < 0)
|
||||
return FatalError("cannot insert exclusive zip name into sys.path");
|
||||
if (PyList_Insert(pathList, 3, g_SharedZipFileName) < 0)
|
||||
return FatalError("cannot insert shared zip name into sys.path");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GetImporterHelper()
|
||||
// Helper which is used to locate the importer for the initscript.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *GetImporterHelper(
|
||||
PyObject *module, // zipimport module
|
||||
PyObject *fileName) // name of file to search
|
||||
{
|
||||
PyObject *importer;
|
||||
|
||||
importer = PyObject_CallMethod(module, "zipimporter", "O", fileName);
|
||||
if (importer)
|
||||
g_InitScriptZipFileName = fileName;
|
||||
else
|
||||
PyErr_Clear();
|
||||
return importer;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GetImporter()
|
||||
// Return the importer which will be used for importing the initialization
|
||||
// script. The executable itself is searched first, followed by the exclusive
|
||||
// zip file and finally by the shared zip file.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int GetImporter(
|
||||
PyObject **importer) // importer (OUT)
|
||||
{
|
||||
PyObject *module;
|
||||
|
||||
module = PyImport_ImportModule("zipimport");
|
||||
if (!module)
|
||||
return FatalError("cannot import zipimport module");
|
||||
*importer = GetImporterHelper(module, g_FileName);
|
||||
if (!*importer) {
|
||||
*importer = GetImporterHelper(module, g_ExclusiveZipFileName);
|
||||
if (!*importer)
|
||||
*importer = GetImporterHelper(module, g_SharedZipFileName);
|
||||
}
|
||||
Py_DECREF(module);
|
||||
if (!*importer)
|
||||
return FatalError("cannot get zipimporter instance");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// PopulateInitScriptDict()
|
||||
// Return the dictionary used by the initialization script.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int PopulateInitScriptDict(
|
||||
PyObject *dict) // dictionary to populate
|
||||
{
|
||||
if (!dict)
|
||||
return FatalError("unable to create temporary dictionary");
|
||||
if (PyDict_SetItemString(dict, "__builtins__", PyEval_GetBuiltins()) < 0)
|
||||
return FatalError("unable to set __builtins__");
|
||||
if (PyDict_SetItemString(dict, "FILE_NAME", g_FileName) < 0)
|
||||
return FatalError("unable to set FILE_NAME");
|
||||
if (PyDict_SetItemString(dict, "DIR_NAME", g_DirName) < 0)
|
||||
return FatalError("unable to set DIR_NAME");
|
||||
if (PyDict_SetItemString(dict, "EXCLUSIVE_ZIP_FILE_NAME",
|
||||
g_ExclusiveZipFileName) < 0)
|
||||
return FatalError("unable to set EXCLUSIVE_ZIP_FILE_NAME");
|
||||
if (PyDict_SetItemString(dict, "SHARED_ZIP_FILE_NAME",
|
||||
g_SharedZipFileName) < 0)
|
||||
return FatalError("unable to set SHARED_ZIP_FILE_NAME");
|
||||
if (PyDict_SetItemString(dict, "INITSCRIPT_ZIP_FILE_NAME",
|
||||
g_InitScriptZipFileName) < 0)
|
||||
return FatalError("unable to set INITSCRIPT_ZIP_FILE_NAME");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ExecuteScript()
|
||||
// Execute the script found within the file.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int ExecuteScript(
|
||||
const char *fileName) // name of file containing Python code
|
||||
{
|
||||
PyObject *importer, *dict, *code, *temp;
|
||||
|
||||
if (SetExecutableName(fileName) < 0)
|
||||
return -1;
|
||||
if (SetPathToSearch() < 0)
|
||||
return -1;
|
||||
importer = NULL;
|
||||
if (GetImporter(&importer) < 0)
|
||||
return -1;
|
||||
|
||||
// create and populate dictionary for initscript module
|
||||
dict = PyDict_New();
|
||||
if (PopulateInitScriptDict(dict) < 0) {
|
||||
Py_XDECREF(dict);
|
||||
Py_DECREF(importer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// locate and execute script
|
||||
code = PyObject_CallMethod(importer, "get_code", "s", "cx_Freeze__init__");
|
||||
Py_DECREF(importer);
|
||||
if (!code)
|
||||
return FatalError("unable to locate initialization module");
|
||||
temp = PyEval_EvalCode( (PyCodeObject*) code, dict, dict);
|
||||
Py_DECREF(code);
|
||||
Py_DECREF(dict);
|
||||
if (!temp)
|
||||
return FatalScriptError();
|
||||
Py_DECREF(temp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,72 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console.c
|
||||
// Main routine for frozen programs which run in a console.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <Python.h>
|
||||
#ifdef __WIN32__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FatalError()
|
||||
// Prints a fatal error.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FatalError(
|
||||
const char *message) // message to print
|
||||
{
|
||||
PyErr_Print();
|
||||
Py_FatalError(message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FatalScriptError()
|
||||
// Prints a fatal error in the initialization script.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FatalScriptError(void)
|
||||
{
|
||||
PyErr_Print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#include "Common.c"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// main()
|
||||
// Main routine for frozen programs.
|
||||
//-----------------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *fileName;
|
||||
char *encoding;
|
||||
|
||||
// initialize Python
|
||||
Py_NoSiteFlag = 1;
|
||||
Py_FrozenFlag = 1;
|
||||
Py_IgnoreEnvironmentFlag = 1;
|
||||
|
||||
encoding = getenv("PYTHONIOENCODING");
|
||||
if (encoding != NULL) {
|
||||
Py_FileSystemDefaultEncoding = strndup(encoding, 100);
|
||||
}
|
||||
|
||||
Py_SetPythonHome("");
|
||||
Py_SetProgramName(argv[0]);
|
||||
fileName = Py_GetProgramFullPath();
|
||||
|
||||
Py_Initialize();
|
||||
PySys_SetArgv(argc, argv);
|
||||
|
||||
|
||||
// do the work
|
||||
if (ExecuteScript(fileName) < 0)
|
||||
return 1;
|
||||
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// ConsoleKeepPath.c
|
||||
// Main routine for frozen programs which need a Python installation to do
|
||||
// their work.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <Python.h>
|
||||
#ifdef __WIN32__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FatalError()
|
||||
// Prints a fatal error.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FatalError(
|
||||
const char *message) // message to print
|
||||
{
|
||||
PyErr_Print();
|
||||
Py_FatalError(message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FatalScriptError()
|
||||
// Prints a fatal error in the initialization script.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FatalScriptError(void)
|
||||
{
|
||||
PyErr_Print();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#include "Common.c"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// main()
|
||||
// Main routine for frozen programs.
|
||||
//-----------------------------------------------------------------------------
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *fileName;
|
||||
|
||||
// initialize Python
|
||||
Py_SetProgramName(argv[0]);
|
||||
fileName = Py_GetProgramFullPath();
|
||||
Py_Initialize();
|
||||
PySys_SetArgv(argc, argv);
|
||||
|
||||
// do the work
|
||||
if (ExecuteScript(fileName) < 0)
|
||||
return 1;
|
||||
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,242 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Win32GUI.c
|
||||
// Main routine for frozen programs written for the Win32 GUI subsystem.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <Python.h>
|
||||
#include <windows.h>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FatalError()
|
||||
// Handle a fatal error.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FatalError(
|
||||
char *a_Message) // message to display
|
||||
{
|
||||
MessageBox(NULL, a_Message, "cx_Freeze Fatal Error", MB_ICONERROR);
|
||||
Py_Finalize();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// StringifyObject()
|
||||
// Stringify a Python object.
|
||||
//-----------------------------------------------------------------------------
|
||||
static char *StringifyObject(
|
||||
PyObject *object, // object to stringify
|
||||
PyObject **stringRep) // string representation
|
||||
{
|
||||
if (object) {
|
||||
*stringRep = PyObject_Str(object);
|
||||
if (*stringRep)
|
||||
return PyString_AS_STRING(*stringRep);
|
||||
return "Unable to stringify";
|
||||
}
|
||||
|
||||
// object is NULL
|
||||
*stringRep = NULL;
|
||||
return "None";
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FatalPythonErrorNoTraceback()
|
||||
// Handle a fatal Python error without traceback.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FatalPythonErrorNoTraceback(
|
||||
PyObject *origType, // exception type
|
||||
PyObject *origValue, // exception value
|
||||
char *message) // message to display
|
||||
{
|
||||
PyObject *typeStrRep, *valueStrRep, *origTypeStrRep, *origValueStrRep;
|
||||
char *totalMessage, *typeStr, *valueStr, *origTypeStr, *origValueStr;
|
||||
PyObject *type, *value, *traceback;
|
||||
int totalMessageLength;
|
||||
char *messageFormat;
|
||||
|
||||
// fetch error and string representations of the error
|
||||
PyErr_Fetch(&type, &value, &traceback);
|
||||
origTypeStr = StringifyObject(origType, &origTypeStrRep);
|
||||
origValueStr = StringifyObject(origValue, &origValueStrRep);
|
||||
typeStr = StringifyObject(type, &typeStrRep);
|
||||
valueStr = StringifyObject(value, &valueStrRep);
|
||||
|
||||
// fill out the message to be displayed
|
||||
messageFormat = "Type: %s\nValue: %s\nOther Type: %s\nOtherValue: %s\n%s";
|
||||
totalMessageLength = strlen(origTypeStr) + strlen(origValueStr) +
|
||||
strlen(typeStr) + strlen(valueStr) + strlen(message) +
|
||||
strlen(messageFormat) + 1;
|
||||
totalMessage = malloc(totalMessageLength);
|
||||
if (!totalMessage)
|
||||
return FatalError("Out of memory!");
|
||||
sprintf(totalMessage, messageFormat, typeStr, valueStr, origTypeStr,
|
||||
origValueStr, message);
|
||||
|
||||
// display the message
|
||||
MessageBox(NULL, totalMessage,
|
||||
"cx_Freeze: Python error in main script (traceback unavailable)",
|
||||
MB_ICONERROR);
|
||||
free(totalMessage);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ArgumentValue()
|
||||
// Return a suitable argument value by replacing NULL with Py_None.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *ArgumentValue(
|
||||
PyObject *object) // argument to massage
|
||||
{
|
||||
if (object) {
|
||||
Py_INCREF(object);
|
||||
return object;
|
||||
}
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HandleSystemExitException()
|
||||
// Handles a system exit exception differently. If an integer value is passed
|
||||
// through then that becomes the exit value; otherwise the string value of the
|
||||
// value passed through is displayed in a message box.
|
||||
//-----------------------------------------------------------------------------
|
||||
static void HandleSystemExitException()
|
||||
{
|
||||
PyObject *type, *value, *traceback, *valueStr;
|
||||
int exitCode = 0;
|
||||
char *message;
|
||||
|
||||
PyErr_Fetch(&type, &value, &traceback);
|
||||
if (PyInstance_Check(value)) {
|
||||
PyObject *code = PyObject_GetAttrString(value, "code");
|
||||
if (code) {
|
||||
Py_DECREF(value);
|
||||
value = code;
|
||||
if (value == Py_None)
|
||||
Py_Exit(0);
|
||||
}
|
||||
}
|
||||
if (PyInt_Check(value))
|
||||
exitCode = PyInt_AsLong(value);
|
||||
else {
|
||||
message = StringifyObject(value, &valueStr);
|
||||
MessageBox(NULL, message, "cx_Freeze: Application Terminated",
|
||||
MB_ICONERROR);
|
||||
Py_XDECREF(valueStr);
|
||||
exitCode = 1;
|
||||
}
|
||||
Py_Exit(exitCode);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FatalScriptError()
|
||||
// Handle a fatal Python error with traceback.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FatalScriptError()
|
||||
{
|
||||
PyObject *type, *value, *traceback, *argsTuple, *module, *method, *result;
|
||||
int tracebackLength, i;
|
||||
char *tracebackStr;
|
||||
|
||||
// if a system exception, handle it specially
|
||||
if (PyErr_ExceptionMatches(PyExc_SystemExit))
|
||||
HandleSystemExitException();
|
||||
|
||||
// get the exception details
|
||||
PyErr_Fetch(&type, &value, &traceback);
|
||||
|
||||
// import the traceback module
|
||||
module = PyImport_ImportModule("traceback");
|
||||
if (!module)
|
||||
return FatalPythonErrorNoTraceback(type, value,
|
||||
"Cannot import traceback module.");
|
||||
|
||||
// get the format_exception method
|
||||
method = PyObject_GetAttrString(module, "format_exception");
|
||||
Py_DECREF(module);
|
||||
if (!method)
|
||||
return FatalPythonErrorNoTraceback(type, value,
|
||||
"Cannot get format_exception method.");
|
||||
|
||||
// create a tuple for the arguments
|
||||
argsTuple = PyTuple_New(3);
|
||||
if (!argsTuple) {
|
||||
Py_DECREF(method);
|
||||
return FatalPythonErrorNoTraceback(type, value,
|
||||
"Cannot create arguments tuple for traceback.");
|
||||
}
|
||||
PyTuple_SET_ITEM(argsTuple, 0, ArgumentValue(type));
|
||||
PyTuple_SET_ITEM(argsTuple, 1, ArgumentValue(value));
|
||||
PyTuple_SET_ITEM(argsTuple, 2, ArgumentValue(traceback));
|
||||
|
||||
// call the format_exception method
|
||||
result = PyObject_CallObject(method, argsTuple);
|
||||
Py_DECREF(method);
|
||||
Py_DECREF(argsTuple);
|
||||
if (!result)
|
||||
return FatalPythonErrorNoTraceback(type, value,
|
||||
"Failed calling format_exception method.");
|
||||
|
||||
// determine length of string representation of formatted traceback
|
||||
tracebackLength = 1;
|
||||
for (i = 0; i < PyList_GET_SIZE(result); i++)
|
||||
tracebackLength += PyString_GET_SIZE(PyList_GET_ITEM(result, i));
|
||||
|
||||
// create a string representation of the formatted traceback
|
||||
tracebackStr = malloc(tracebackLength);
|
||||
if (!tracebackStr) {
|
||||
Py_DECREF(result);
|
||||
return FatalError("Out of memory!");
|
||||
}
|
||||
tracebackStr[0] = '\0';
|
||||
for (i = 0; i < PyList_GET_SIZE(result); i++)
|
||||
strcat(tracebackStr, PyString_AS_STRING(PyList_GET_ITEM(result, i)));
|
||||
Py_DECREF(result);
|
||||
|
||||
// bring up the error
|
||||
MessageBox(NULL, tracebackStr, "cx_Freeze: Python error in main script",
|
||||
MB_ICONERROR);
|
||||
Py_Finalize();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#include "Common.c"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// WinMain()
|
||||
// Main routine for the executable in Windows.
|
||||
//-----------------------------------------------------------------------------
|
||||
int WINAPI WinMain(
|
||||
HINSTANCE instance, // handle to application
|
||||
HINSTANCE prevInstance, // previous handle to application
|
||||
LPSTR commandLine, // command line
|
||||
int showFlag) // show flag
|
||||
{
|
||||
const char *fileName;
|
||||
|
||||
// initialize Python
|
||||
Py_NoSiteFlag = 1;
|
||||
Py_FrozenFlag = 1;
|
||||
Py_IgnoreEnvironmentFlag = 1;
|
||||
Py_SetPythonHome("");
|
||||
Py_SetProgramName(__argv[0]);
|
||||
fileName = Py_GetProgramFullPath();
|
||||
Py_Initialize();
|
||||
PySys_SetArgv(__argc, __argv);
|
||||
|
||||
// do the work
|
||||
if (ExecuteScript(fileName) < 0)
|
||||
return 1;
|
||||
|
||||
// terminate Python
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
STRINGTABLE
|
||||
{
|
||||
1, "Just to ensure that buggy EndUpdateResource doesn't fall over."
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
#include "dummy.rc"
|
||||
|
||||
1 24 source/bases/manifest.txt
|
@ -1,418 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// util.c
|
||||
// Shared library for use by cx_Freeze.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
#pragma pack(2)
|
||||
|
||||
typedef struct {
|
||||
BYTE bWidth; // Width, in pixels, of the image
|
||||
BYTE bHeight; // Height, in pixels, of the image
|
||||
BYTE bColorCount; // Number of colors in image
|
||||
BYTE bReserved; // Reserved ( must be 0)
|
||||
WORD wPlanes; // Color Planes
|
||||
WORD wBitCount; // Bits per pixel
|
||||
DWORD dwBytesInRes; // How many bytes in this resource?
|
||||
DWORD dwImageOffset; // Where in the file is this image?
|
||||
} ICONDIRENTRY;
|
||||
|
||||
typedef struct {
|
||||
WORD idReserved; // Reserved (must be 0)
|
||||
WORD idType; // Resource Type (1 for icons)
|
||||
WORD idCount; // How many images?
|
||||
ICONDIRENTRY idEntries[0]; // An entry for each image
|
||||
} ICONDIR;
|
||||
|
||||
typedef struct {
|
||||
BYTE bWidth; // Width, in pixels, of the image
|
||||
BYTE bHeight; // Height, in pixels, of the image
|
||||
BYTE bColorCount; // Number of colors in image
|
||||
BYTE bReserved; // Reserved ( must be 0)
|
||||
WORD wPlanes; // Color Planes
|
||||
WORD wBitCount; // Bits per pixel
|
||||
DWORD dwBytesInRes; // How many bytes in this resource?
|
||||
WORD nID; // resource ID
|
||||
} GRPICONDIRENTRY;
|
||||
|
||||
typedef struct {
|
||||
WORD idReserved; // Reserved (must be 0)
|
||||
WORD idType; // Resource Type (1 for icons)
|
||||
WORD idCount; // How many images?
|
||||
GRPICONDIRENTRY idEntries[0]; // An entry for each image
|
||||
} GRPICONDIR;
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Globals
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef WIN32
|
||||
static PyObject *g_BindErrorException = NULL;
|
||||
static PyObject *g_ImageNames = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
//-----------------------------------------------------------------------------
|
||||
// BindStatusRoutine()
|
||||
// Called by BindImageEx() at various points. This is used to determine the
|
||||
// dependency tree which is later examined by cx_Freeze.
|
||||
//-----------------------------------------------------------------------------
|
||||
static BOOL __stdcall BindStatusRoutine(
|
||||
IMAGEHLP_STATUS_REASON reason, // reason called
|
||||
PSTR imageName, // name of image being examined
|
||||
PSTR dllName, // name of DLL
|
||||
ULONG virtualAddress, // computed virtual address
|
||||
ULONG parameter) // parameter (value depends on reason)
|
||||
{
|
||||
char fileName[MAX_PATH + 1];
|
||||
|
||||
switch (reason) {
|
||||
case BindImportModule:
|
||||
if (!SearchPath(NULL, dllName, NULL, sizeof(fileName), fileName,
|
||||
NULL))
|
||||
return FALSE;
|
||||
Py_INCREF(Py_None);
|
||||
if (PyDict_SetItemString(g_ImageNames, fileName, Py_None) < 0)
|
||||
return FALSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GetFileData()
|
||||
// Return the data for the given file.
|
||||
//-----------------------------------------------------------------------------
|
||||
static int GetFileData(
|
||||
const char *fileName, // name of file to read
|
||||
char **data) // pointer to data (OUT)
|
||||
{
|
||||
DWORD numberOfBytesRead, dataSize;
|
||||
HANDLE file;
|
||||
|
||||
file = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
dataSize = GetFileSize(file, NULL);
|
||||
if (dataSize == INVALID_FILE_SIZE) {
|
||||
CloseHandle(file);
|
||||
return -1;
|
||||
}
|
||||
*data = PyMem_Malloc(dataSize);
|
||||
if (!*data) {
|
||||
CloseHandle(file);
|
||||
return -1;
|
||||
}
|
||||
if (!ReadFile(file, *data, dataSize, &numberOfBytesRead, NULL)) {
|
||||
CloseHandle(file);
|
||||
return -1;
|
||||
}
|
||||
CloseHandle(file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CreateGroupIconResource()
|
||||
// Return the group icon resource given the icon file data.
|
||||
//-----------------------------------------------------------------------------
|
||||
static GRPICONDIR *CreateGroupIconResource(
|
||||
ICONDIR *iconDir, // icon information
|
||||
DWORD *resourceSize) // size of resource (OUT)
|
||||
{
|
||||
GRPICONDIR *groupIconDir;
|
||||
int i;
|
||||
|
||||
*resourceSize = sizeof(GRPICONDIR) +
|
||||
sizeof(GRPICONDIRENTRY) * iconDir->idCount;
|
||||
groupIconDir = PyMem_Malloc(*resourceSize);
|
||||
if (!groupIconDir)
|
||||
return NULL;
|
||||
groupIconDir->idReserved = iconDir->idReserved;
|
||||
groupIconDir->idType = iconDir->idType;
|
||||
groupIconDir->idCount = iconDir->idCount;
|
||||
for (i = 0; i < iconDir->idCount; i++) {
|
||||
groupIconDir->idEntries[i].bWidth = iconDir->idEntries[i].bWidth;
|
||||
groupIconDir->idEntries[i].bHeight = iconDir->idEntries[i].bHeight;
|
||||
groupIconDir->idEntries[i].bColorCount =
|
||||
iconDir->idEntries[i].bColorCount;
|
||||
groupIconDir->idEntries[i].bReserved = iconDir->idEntries[i].bReserved;
|
||||
groupIconDir->idEntries[i].wPlanes = iconDir->idEntries[i].wPlanes;
|
||||
groupIconDir->idEntries[i].wBitCount = iconDir->idEntries[i].wBitCount;
|
||||
groupIconDir->idEntries[i].dwBytesInRes =
|
||||
iconDir->idEntries[i].dwBytesInRes;
|
||||
groupIconDir->idEntries[i].nID = i + 1;
|
||||
}
|
||||
|
||||
return groupIconDir;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ExtAddIcon()
|
||||
// Add the icon as a resource to the specified file.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *ExtAddIcon(
|
||||
PyObject *self, // passthrough argument
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
char *executableName, *iconName, *data, *iconData;
|
||||
GRPICONDIR *groupIconDir;
|
||||
DWORD resourceSize;
|
||||
ICONDIR *iconDir;
|
||||
BOOL succeeded;
|
||||
HANDLE handle;
|
||||
int i;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss", &executableName, &iconName))
|
||||
return NULL;
|
||||
|
||||
// begin updating the executable
|
||||
handle = BeginUpdateResource(executableName, FALSE);
|
||||
if (!handle) {
|
||||
PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
|
||||
GetLastError(), executableName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// first attempt to get the data from the icon file
|
||||
data = NULL;
|
||||
succeeded = TRUE;
|
||||
groupIconDir = NULL;
|
||||
if (GetFileData(iconName, &data) < 0)
|
||||
succeeded = FALSE;
|
||||
iconDir = (ICONDIR*) data;
|
||||
|
||||
// next, attempt to add a group icon resource
|
||||
if (succeeded) {
|
||||
groupIconDir = CreateGroupIconResource(iconDir, &resourceSize);
|
||||
if (groupIconDir)
|
||||
succeeded = UpdateResource(handle, RT_GROUP_ICON,
|
||||
MAKEINTRESOURCE(1),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
|
||||
groupIconDir, resourceSize);
|
||||
else succeeded = FALSE;
|
||||
}
|
||||
|
||||
// next, add each icon as a resource
|
||||
if (succeeded) {
|
||||
for (i = 0; i < iconDir->idCount; i++) {
|
||||
iconData = &data[iconDir->idEntries[i].dwImageOffset];
|
||||
resourceSize = iconDir->idEntries[i].dwBytesInRes;
|
||||
succeeded = UpdateResource(handle, RT_ICON, MAKEINTRESOURCE(i + 1),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), iconData,
|
||||
resourceSize);
|
||||
if (!succeeded)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// finish writing the resource (or discarding the changes upon an error)
|
||||
if (!EndUpdateResource(handle, !succeeded)) {
|
||||
if (succeeded) {
|
||||
succeeded = FALSE;
|
||||
PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
|
||||
GetLastError(), executableName);
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
if (groupIconDir)
|
||||
PyMem_Free(groupIconDir);
|
||||
if (data)
|
||||
PyMem_Free(data);
|
||||
if (!succeeded)
|
||||
return NULL;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ExtBeginUpdateResource()
|
||||
// Wrapper for BeginUpdateResource().
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *ExtBeginUpdateResource(
|
||||
PyObject *self, // passthrough argument
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
BOOL deleteExistingResources;
|
||||
char *fileName;
|
||||
HANDLE handle;
|
||||
|
||||
deleteExistingResources = TRUE;
|
||||
if (!PyArg_ParseTuple(args, "s|i", &fileName, &deleteExistingResources))
|
||||
return NULL;
|
||||
handle = BeginUpdateResource(fileName, deleteExistingResources);
|
||||
if (!handle) {
|
||||
PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
|
||||
GetLastError(), fileName);
|
||||
return NULL;
|
||||
}
|
||||
return PyInt_FromLong((long) handle);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ExtUpdateResource()
|
||||
// Wrapper for UpdateResource().
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *ExtUpdateResource(
|
||||
PyObject *self, // passthrough argument
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
int resourceType, resourceId, resourceDataSize;
|
||||
char *resourceData;
|
||||
HANDLE handle;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iiis#", &handle, &resourceType, &resourceId,
|
||||
&resourceData, &resourceDataSize))
|
||||
return NULL;
|
||||
if (!UpdateResource(handle, MAKEINTRESOURCE(resourceType),
|
||||
MAKEINTRESOURCE(resourceId),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), resourceData,
|
||||
resourceDataSize)) {
|
||||
PyErr_SetExcFromWindowsErr(PyExc_WindowsError, GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ExtEndUpdateResource()
|
||||
// Wrapper for EndUpdateResource().
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *ExtEndUpdateResource(
|
||||
PyObject *self, // passthrough argument
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
BOOL discardChanges;
|
||||
HANDLE handle;
|
||||
|
||||
discardChanges = FALSE;
|
||||
if (!PyArg_ParseTuple(args, "i|i", &handle, &discardChanges))
|
||||
return NULL;
|
||||
if (!EndUpdateResource(handle, discardChanges)) {
|
||||
PyErr_SetExcFromWindowsErr(PyExc_WindowsError, GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ExtGetDependentFiles()
|
||||
// Return a list of files that this file depends on.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *ExtGetDependentFiles(
|
||||
PyObject *self, // passthrough argument
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
PyObject *results;
|
||||
char *imageName;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &imageName))
|
||||
return NULL;
|
||||
g_ImageNames = PyDict_New();
|
||||
if (!g_ImageNames)
|
||||
return NULL;
|
||||
if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
|
||||
imageName, NULL, NULL, BindStatusRoutine)) {
|
||||
Py_DECREF(g_ImageNames);
|
||||
PyErr_SetExcFromWindowsErrWithFilename(g_BindErrorException,
|
||||
GetLastError(), imageName);
|
||||
return NULL;
|
||||
}
|
||||
results = PyDict_Keys(g_ImageNames);
|
||||
Py_DECREF(g_ImageNames);
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ExtGetSystemDir()
|
||||
// Return the Windows directory (C:\Windows for example).
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *ExtGetSystemDir(
|
||||
PyObject *self, // passthrough argument
|
||||
PyObject *args) // arguments (ignored)
|
||||
{
|
||||
char dir[MAX_PATH + 1];
|
||||
|
||||
if (GetSystemDirectory(dir, sizeof(dir)))
|
||||
return PyString_FromString(dir);
|
||||
PyErr_SetExcFromWindowsErr(PyExc_RuntimeError, GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ExtSetOptimizeFlag()
|
||||
// Set the optimize flag as needed.
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyObject *ExtSetOptimizeFlag(
|
||||
PyObject *self, // passthrough argument
|
||||
PyObject *args) // arguments
|
||||
{
|
||||
if (!PyArg_ParseTuple(args, "i", &Py_OptimizeFlag))
|
||||
return NULL;
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
static PyMethodDef g_ModuleMethods[] = {
|
||||
{ "SetOptimizeFlag", ExtSetOptimizeFlag, METH_VARARGS },
|
||||
#ifdef WIN32
|
||||
{ "BeginUpdateResource", ExtBeginUpdateResource, METH_VARARGS },
|
||||
{ "UpdateResource", ExtUpdateResource, METH_VARARGS },
|
||||
{ "EndUpdateResource", ExtEndUpdateResource, METH_VARARGS },
|
||||
{ "AddIcon", ExtAddIcon, METH_VARARGS },
|
||||
{ "GetDependentFiles", ExtGetDependentFiles, METH_VARARGS },
|
||||
{ "GetSystemDir", ExtGetSystemDir, METH_NOARGS },
|
||||
#endif
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// initutil()
|
||||
// Initialization routine for the shared libary.
|
||||
//-----------------------------------------------------------------------------
|
||||
void initutil(void)
|
||||
{
|
||||
PyObject *module;
|
||||
|
||||
module = Py_InitModule("cx_Freeze.util", g_ModuleMethods);
|
||||
if (!module)
|
||||
return;
|
||||
#ifdef WIN32
|
||||
g_BindErrorException = PyErr_NewException("cx_Freeze.util.BindError",
|
||||
NULL, NULL);
|
||||
if (!g_BindErrorException)
|
||||
return;
|
||||
if (PyModule_AddObject(module, "BindError", g_BindErrorException) < 0)
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ class Linux32(VMInstaller):
|
||||
VM_NAME = 'gentoo32_build'
|
||||
VM = '/vmware/bin/gentoo32_build'
|
||||
FREEZE_COMMAND = 'linux_freeze'
|
||||
FREEZE_TEMPLATE = 'sudo python -OO setup.py {freeze_command}'
|
||||
|
||||
|
||||
class Linux64(Linux32):
|
||||
|
@ -46,7 +46,6 @@ class LinuxFreeze(Command):
|
||||
'/usr/lib/libunrar.so',
|
||||
'/usr/lib/libchm.so.0',
|
||||
'/usr/lib/libsqlite3.so.0',
|
||||
'/usr/lib/libsqlite3.so.0',
|
||||
'/usr/lib/libmng.so.1',
|
||||
'/usr/lib/libpodofo.so.0.8.2',
|
||||
'/lib/libz.so.1',
|
||||
|
@ -6,58 +6,57 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import sys, os, shutil, platform, subprocess, stat, py_compile, glob
|
||||
import sys, os, shutil, platform, subprocess, stat, py_compile, glob, \
|
||||
textwrap, tarfile
|
||||
|
||||
from setup import Command, modules, basenames, functions
|
||||
|
||||
is64bit = platform.architecture()[0] == '64bit'
|
||||
arch = 'x86_64' if is64bit else 'i686'
|
||||
ffi = '/usr/lib/libffi.so.5' if is64bit else '/usr/lib/gcc/i686-pc-linux-gnu/4.4.1/libffi.so.4'
|
||||
from setup import Command, modules, basenames, functions, __version__, \
|
||||
__appname__
|
||||
|
||||
SITE_PACKAGES = ['IPython', 'PIL', 'dateutil', 'dns', 'PyQt4', 'mechanize',
|
||||
'sip.so', 'BeautifulSoup.py', 'cssutils', 'encutils', 'lxml',
|
||||
'sipconfig.py', 'xdg']
|
||||
|
||||
QTDIR = '/usr/lib/qt4'
|
||||
QTDLLS = ('QtCore', 'QtGui', 'QtNetwork', 'QtSvg', 'QtXml', 'QtWebKit', 'QtDBus')
|
||||
|
||||
|
||||
binary_includes = [
|
||||
'/usr/bin/pdftohtml',
|
||||
'/usr/lib/libwmflite-0.2.so.7',
|
||||
'/usr/lib/liblcms.so.1',
|
||||
'/usr/lib/libunrar.so',
|
||||
'/usr/lib/libsqlite3.so.0',
|
||||
'/usr/lib/libsqlite3.so.0',
|
||||
'/usr/lib/libmng.so.1',
|
||||
'/usr/lib/libpodofo.so.0.6.99',
|
||||
'/usr/lib/libpodofo.so.0.8.4',
|
||||
'/lib/libz.so.1',
|
||||
'/usr/lib/libtiff.so.3',
|
||||
'/usr/lib/libtiff.so.5',
|
||||
'/lib/libbz2.so.1',
|
||||
'/usr/lib/libpoppler.so.5',
|
||||
'/usr/lib/libpoppler.so.7',
|
||||
'/usr/lib/libxml2.so.2',
|
||||
'/usr/lib/libopenjpeg.so.2',
|
||||
'/usr/lib/libxslt.so.1',
|
||||
'/usr/lib/libjpeg.so.7',
|
||||
'/usr/lib/libjpeg.so.8',
|
||||
'/usr/lib/libxslt.so.1',
|
||||
'/usr/lib/libgthread-2.0.so.0',
|
||||
'/usr/lib/gcc/***-pc-linux-gnu/4.4.1/libstdc++.so.6'.replace('***',
|
||||
arch),
|
||||
ffi,
|
||||
'/usr/lib/libpng12.so.0',
|
||||
'/usr/lib/libpng14.so.14',
|
||||
'/usr/lib/libexslt.so.0',
|
||||
'/usr/lib/libMagickWand.so.2',
|
||||
'/usr/lib/libMagickCore.so.2',
|
||||
'/usr/lib/libMagickWand.so.4',
|
||||
'/usr/lib/libMagickCore.so.4',
|
||||
'/usr/lib/libgcrypt.so.11',
|
||||
'/usr/lib/libgpg-error.so.0',
|
||||
'/usr/lib/libphonon.so.4',
|
||||
'/usr/lib/libssl.so.0.9.8',
|
||||
'/usr/lib/libcrypto.so.0.9.8',
|
||||
'/usr/lib/libssl.so.1.0.0',
|
||||
'/usr/lib/libcrypto.so.1.0.0',
|
||||
'/lib/libreadline.so.6',
|
||||
'/usr/lib/libchm.so.0',
|
||||
'/usr/lib/liblcms2.so.2',
|
||||
]
|
||||
binary_includes += [os.path.join(QTDIR, 'lib%s.so.4'%x) for x in QTDLLS]
|
||||
|
||||
SITE_PACKAGES = ['IPython', 'PIL', 'dateutil', 'dns', 'PyQt4', 'mechanize',
|
||||
'sip.so', 'BeautifulSoup.py', 'ClientForm.py', 'lxml']
|
||||
is64bit = platform.architecture()[0] == '64bit'
|
||||
arch = 'x86_64' if is64bit else 'i686'
|
||||
|
||||
class LinuxFreeze2(Command):
|
||||
|
||||
class LinuxFreeze(Command):
|
||||
|
||||
def run(self, opts):
|
||||
self.drop_privileges()
|
||||
@ -68,11 +67,12 @@ class LinuxFreeze2(Command):
|
||||
self.lib_dir = self.j(self.base, 'lib')
|
||||
self.bin_dir = self.j(self.base, 'bin')
|
||||
|
||||
#self.initbase()
|
||||
#self.copy_libs()
|
||||
#self.copy_python()
|
||||
#self.compile_mount_helper()
|
||||
self.initbase()
|
||||
self.copy_libs()
|
||||
self.copy_python()
|
||||
self.compile_mount_helper()
|
||||
self.build_launchers()
|
||||
self.create_tarfile()
|
||||
|
||||
def initbase(self):
|
||||
if os.path.exists(self.base):
|
||||
@ -83,7 +83,21 @@ class LinuxFreeze2(Command):
|
||||
self.info('Copying libs...')
|
||||
os.mkdir(self.lib_dir)
|
||||
os.mkdir(self.bin_dir)
|
||||
for x in binary_includes:
|
||||
|
||||
gcc = subprocess.Popen(["gcc-config", "-c"], stdout=subprocess.PIPE).communicate()[0]
|
||||
chost, _, gcc = gcc.rpartition('-')
|
||||
gcc_lib = '/usr/lib/gcc/%s/%s/'%(chost.strip(), gcc.strip())
|
||||
stdcpp = gcc_lib+'libstdc++.so.?'
|
||||
stdcpp = glob.glob(stdcpp)[-1]
|
||||
ffi = gcc_lib+'libffi.so.?'
|
||||
ffi = glob.glob(ffi)
|
||||
if ffi:
|
||||
ffi = ffi[-1]
|
||||
else:
|
||||
ffi = glob.glob('/usr/lib/libffi.so.?')[-1]
|
||||
|
||||
|
||||
for x in binary_includes + [stdcpp, ffi]:
|
||||
dest = self.bin_dir if '/bin/' in x else self.lib_dir
|
||||
shutil.copy2(x, dest)
|
||||
shutil.copy2('/usr/lib/libpython%s.so.1.0'%self.py_ver, dest)
|
||||
@ -109,7 +123,7 @@ class LinuxFreeze2(Command):
|
||||
'linux_mount_helper.c'), '-o', dest])
|
||||
os.chown(dest, 0, 0)
|
||||
os.chmod(dest, stat.S_ISUID|stat.S_ISGID|stat.S_IRUSR|stat.S_IWUSR|\
|
||||
stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
|
||||
stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH|stat.S_IRGRP|stat.S_IROTH)
|
||||
self.drop_privileges()
|
||||
|
||||
def copy_python(self):
|
||||
@ -117,27 +131,30 @@ class LinuxFreeze2(Command):
|
||||
|
||||
def ignore_in_lib(base, items):
|
||||
ans = []
|
||||
for x in items:
|
||||
x = os.path.join(base, x)
|
||||
for y in items:
|
||||
x = os.path.join(base, y)
|
||||
if (os.path.isfile(x) and os.path.splitext(x)[1] in ('.so',
|
||||
'.py')) or \
|
||||
(os.path.isdir(x) and x in ('.svn', '.bzr', 'test')):
|
||||
(os.path.isdir(x) and x not in ('.svn', '.bzr', 'test', 'tests',
|
||||
'testing')):
|
||||
continue
|
||||
ans.append(x)
|
||||
ans.append(y)
|
||||
return ans
|
||||
|
||||
srcdir = self.j('/usr/lib/python'+self.py_ver)
|
||||
self.py_dir = self.j(self.lib_dir, self.b(srcdir))
|
||||
os.mkdir(self.py_dir)
|
||||
if not os.path.exists(self.py_dir):
|
||||
os.mkdir(self.py_dir)
|
||||
|
||||
for x in os.listdir(srcdir):
|
||||
y = self.j(srcdir, x)
|
||||
ext = os.path.splitext(x)[1]
|
||||
if os.path.isdir(y) and x not in ('test', 'hotshot', 'distutils',
|
||||
'site-packages', 'idlelib', 'test', 'lib2to3'):
|
||||
'site-packages', 'idlelib', 'lib2to3', 'dist-packages'):
|
||||
shutil.copytree(y, self.j(self.py_dir, x),
|
||||
ignore=ignore_in_lib)
|
||||
if os.path.isfile(y) and ext in ('.py', '.so'):
|
||||
if os.path.isfile(y) and ext in ('.py', '.so') and \
|
||||
self.b(y) not in ('pdflib_py.so',):
|
||||
shutil.copy2(y, self.py_dir)
|
||||
|
||||
srcdir = self.j(srcdir, 'site-packages')
|
||||
@ -155,13 +172,19 @@ class LinuxFreeze2(Command):
|
||||
for x in os.listdir(self.SRC):
|
||||
shutil.copytree(self.j(self.SRC, x), self.j(dest, x),
|
||||
ignore=ignore_in_lib)
|
||||
for x in ('translations', 'manual'):
|
||||
for x in ('manual', 'trac'):
|
||||
x = self.j(dest, 'calibre', x)
|
||||
shutil.rmtree(x)
|
||||
if os.path.exists(x):
|
||||
shutil.rmtree(x)
|
||||
|
||||
for x in glob.glob(self.j(dest, 'calibre', 'translations', '*.po')):
|
||||
os.remove(x)
|
||||
|
||||
shutil.copytree(self.j(self.src_root, 'resources'), self.j(self.base,
|
||||
'resources'))
|
||||
|
||||
self.create_site_py()
|
||||
|
||||
for x in os.walk(self.py_dir):
|
||||
for f in x[-1]:
|
||||
if f.endswith('.py'):
|
||||
@ -176,17 +199,37 @@ class LinuxFreeze2(Command):
|
||||
except:
|
||||
self.warn('Failed to byte-compile', y)
|
||||
|
||||
def run_builder(self, cmd):
|
||||
|
||||
def run_builder(self, cmd, verbose=True):
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
self.info(*cmd)
|
||||
self.info(p.stdout.read())
|
||||
self.info(p.stderr.read())
|
||||
if verbose:
|
||||
self.info(*cmd)
|
||||
x = p.stdout.read() + p.stderr.read()
|
||||
if x.strip():
|
||||
self.info(x.strip())
|
||||
|
||||
if p.wait() != 0:
|
||||
self.info('Failed to run builder')
|
||||
sys.exit(1)
|
||||
|
||||
def create_tarfile(self):
|
||||
self.info('Creating archive...')
|
||||
dist = os.path.join(self.d(self.SRC), 'dist',
|
||||
'%s-%s-%s.tar.bz2'%(__appname__, __version__, arch))
|
||||
with tarfile.open(dist, mode='w:bz2',
|
||||
format=tarfile.PAX_FORMAT) as tf:
|
||||
cwd = os.getcwd()
|
||||
os.chdir(self.base)
|
||||
try:
|
||||
for x in os.listdir('.'):
|
||||
tf.add(x)
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
self.info('Archive %s created: %.2f MB'%(dist,
|
||||
os.stat(dist).st_size/(1024.**2)))
|
||||
|
||||
|
||||
def build_launchers(self):
|
||||
self.obj_dir = self.j(self.src_root, 'build', 'launcher')
|
||||
if not os.path.exists(self.obj_dir):
|
||||
@ -195,7 +238,7 @@ class LinuxFreeze2(Command):
|
||||
sources = [self.j(base, x) for x in ['util.c']]
|
||||
headers = [self.j(base, x) for x in ['util.h']]
|
||||
objects = [self.j(self.obj_dir, self.b(x)+'.o') for x in sources]
|
||||
cflags = '-W -Wall -c -O2 -pipe -DPYTHON_VER="python%s"'%self.py_ver
|
||||
cflags = '-fno-strict-aliasing -W -Wall -c -O2 -pipe -DPYTHON_VER="python%s"'%self.py_ver
|
||||
cflags = cflags.split() + ['-I/usr/include/python'+self.py_ver]
|
||||
for src, obj in zip(sources, objects):
|
||||
if not self.newer(obj, headers+[src, __file__]): continue
|
||||
@ -210,34 +253,115 @@ class LinuxFreeze2(Command):
|
||||
self.run_builder(cmd)
|
||||
|
||||
src = self.j(base, 'main.c')
|
||||
|
||||
modules['console'].append('calibre.linux')
|
||||
basenames['console'].append('calibre_postinstall')
|
||||
functions['console'].append('main')
|
||||
for typ in ('console', 'gui', ):
|
||||
self.info('Processing %s launchers'%typ)
|
||||
for mod, bname, func in zip(modules[typ], basenames[typ],
|
||||
functions[typ]):
|
||||
xflags = list(cflags)
|
||||
xflags += ['-DGUI_APP='+('1' if type == 'gui' else '0')]
|
||||
xflags += ['-DGUI_APP='+('1' if typ == 'gui' else '0')]
|
||||
xflags += ['-DMODULE="%s"'%mod, '-DBASENAME="%s"'%bname,
|
||||
'-DFUNCTION="%s"'%func]
|
||||
|
||||
launcher = textwrap.dedent('''\
|
||||
#!/bin/sh
|
||||
path=`readlink -e $0`
|
||||
base=`dirname $path`
|
||||
lib=$base/lib
|
||||
export LD_LIBRARY_PATH=$lib:$LD_LIBRARY_PATH
|
||||
export MAGICK_CONFIGURE_PATH=$lib/ImageMagick/config
|
||||
export MAGICK_CODER_MODULE_PATH=$lib/ImageMagick/modules-Q16/coders
|
||||
export MAGICK_CODER_FILTER_PATH=$lib/ImageMagick/modules-Q16/filters
|
||||
$base/bin/{0} "$@"
|
||||
''')
|
||||
|
||||
dest = self.j(self.obj_dir, bname+'.o')
|
||||
if self.newer(dest, [src, __file__]+headers):
|
||||
self.info('Compiling', bname)
|
||||
cmd = ['gcc'] + xflags + [src, '-o', dest]
|
||||
self.run_builder(cmd)
|
||||
self.run_builder(cmd, verbose=False)
|
||||
exe = self.j(self.bin_dir, bname)
|
||||
sh = self.j(self.base, bname)
|
||||
with open(sh, 'wb') as f:
|
||||
f.write(launcher.format(bname))
|
||||
os.chmod(sh,
|
||||
stat.S_IREAD|stat.S_IEXEC|stat.S_IWRITE|stat.S_IRGRP|stat.S_IXGRP|stat.S_IROTH|stat.S_IXOTH)
|
||||
|
||||
if self.newer(exe, [dest, __file__]):
|
||||
self.info('Linking', bname)
|
||||
cmd = ['gcc', '-O2', '-Wl,--rpath=$ORIGIN/../lib',
|
||||
cmd = ['gcc', '-O2',
|
||||
'-o', exe,
|
||||
dest,
|
||||
'-L'+self.lib_dir,
|
||||
'-lcalibre-launcher',
|
||||
]
|
||||
|
||||
self.run_builder(cmd)
|
||||
self.run_builder(cmd, verbose=False)
|
||||
|
||||
|
||||
def create_site_py(self): # {{{
|
||||
with open(self.j(self.py_dir, 'site.py'), 'wb') as f:
|
||||
f.write(textwrap.dedent('''\
|
||||
import sys
|
||||
import encodings
|
||||
import __builtin__
|
||||
import locale
|
||||
import os
|
||||
import codecs
|
||||
|
||||
def set_default_encoding():
|
||||
locale.setlocale(locale.LC_ALL, '')
|
||||
enc = locale.getdefaultlocale()[1]
|
||||
if not enc:
|
||||
enc = locale.nl_langinfo(locale.CODESET)
|
||||
if not enc or enc.lower() == 'ascii':
|
||||
enc = 'UTF-8'
|
||||
enc = codecs.lookup(enc).name
|
||||
sys.setdefaultencoding(enc)
|
||||
del sys.setdefaultencoding
|
||||
|
||||
class _Helper(object):
|
||||
"""Define the builtin 'help'.
|
||||
This is a wrapper around pydoc.help (with a twist).
|
||||
|
||||
"""
|
||||
|
||||
def __repr__(self):
|
||||
return "Type help() for interactive help, " \
|
||||
"or help(object) for help about object."
|
||||
def __call__(self, *args, **kwds):
|
||||
import pydoc
|
||||
return pydoc.help(*args, **kwds)
|
||||
|
||||
def set_helper():
|
||||
__builtin__.help = _Helper()
|
||||
|
||||
def set_qt_plugin_path():
|
||||
from PyQt4.Qt import QCoreApplication
|
||||
paths = list(map(unicode, QCoreApplication.libraryPaths()))
|
||||
paths.insert(0, sys.frozen_path + '/lib/qt_plugins')
|
||||
QCoreApplication.setLibraryPaths(paths)
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
sys.argv[0] = sys.calibre_basename
|
||||
set_default_encoding()
|
||||
set_helper()
|
||||
set_qt_plugin_path()
|
||||
mod = __import__(sys.calibre_module, fromlist=[1])
|
||||
func = getattr(mod, sys.calibre_function)
|
||||
return func()
|
||||
except SystemExit:
|
||||
raise
|
||||
except:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return 1
|
||||
'''))
|
||||
# }}}
|
||||
|
||||
|
||||
|
@ -11,10 +11,8 @@ static char exe_path[PATH_MAX];
|
||||
static char base_dir[PATH_MAX];
|
||||
static char bin_dir[PATH_MAX];
|
||||
static char lib_dir[PATH_MAX];
|
||||
static char qt_dir[PATH_MAX];
|
||||
static char extensions_dir[PATH_MAX];
|
||||
static char resources_dir[PATH_MAX];
|
||||
static char magick_dir[PATH_MAX];
|
||||
|
||||
void set_gui_app(bool yes) { GUI_APP = yes; }
|
||||
|
||||
@ -26,7 +24,8 @@ int report_error(const char *msg, int code) {
|
||||
int report_libc_error(const char *msg) {
|
||||
char buf[2000];
|
||||
int err = errno;
|
||||
snprintf("%s::%s", 2000, msg, strerror(err));
|
||||
|
||||
snprintf(buf, 2000, "%s::%s", msg, strerror(err));
|
||||
return report_error(buf, err);
|
||||
}
|
||||
|
||||
@ -122,54 +121,31 @@ static void get_paths()
|
||||
exit(report_error("No path separators in executable path", EXIT_FAILURE));
|
||||
}
|
||||
strncat(base_dir, exe_path, p - exe_path);
|
||||
strcat(base_dir, "\0");
|
||||
p = rindex(base_dir, '/');
|
||||
if (p == NULL) {
|
||||
exit(report_error("Only one path separator in executable path", EXIT_FAILURE));
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
snprintf(bin_dir, PATH_MAX, "%s/bin", base_dir);
|
||||
snprintf(lib_dir, PATH_MAX, "%s/lib", base_dir);
|
||||
snprintf(magick_dir, PATH_MAX, "%s/ImageMagick", lib_dir);
|
||||
snprintf(qt_dir, PATH_MAX, "%s/qt_plugins", lib_dir);
|
||||
snprintf(resources_dir, PATH_MAX, "%s/resources", base_dir);
|
||||
snprintf(extensions_dir, PATH_MAX, "%s/%s/site-packages/calibre/plugins", lib_dir, PYTHON_VER);
|
||||
}
|
||||
|
||||
void init_env() {
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (setenv("QT_PLUGIN_PATH", qt_dir, 1) == -1)
|
||||
exit(report_libc_error("Failed to set environment variable"));
|
||||
|
||||
snprintf(buf, PATH_MAX, "%s/config", magick_dir);
|
||||
if (setenv("MAGICK_CONFIGURE_PATH", buf, 1) == -1)
|
||||
exit(report_libc_error("Failed to set environment variable"));
|
||||
|
||||
snprintf(buf, PATH_MAX, "%s/modules-Q16/coders", magick_dir);
|
||||
if (setenv("MAGICK_CODER_MODULE_PATH", buf, 1) == -1)
|
||||
exit(report_libc_error("Failed to set environment variable"));
|
||||
|
||||
snprintf(buf, PATH_MAX, "%s/modules-Q16/filters", magick_dir);
|
||||
if (setenv("MAGICK_CODER_FILTER_PATH", buf, 1) == -1)
|
||||
exit(report_libc_error("Failed to set environment variable"));
|
||||
|
||||
if (setenv("PYTHONIOENCODING", "utf-8", 1) == -1)
|
||||
exit(report_libc_error("Failed to set environment variable"));
|
||||
|
||||
if (setenv("PYTHONHOME", base_dir, 1) == -1)
|
||||
exit(report_libc_error("Failed to set environment variable"));
|
||||
|
||||
}
|
||||
|
||||
void setup_stream(const char *name, const char *errors) {
|
||||
PyObject *stream;
|
||||
char *buf = (char *)calloc(100, sizeof(char));
|
||||
if (!buf) OOM;
|
||||
char buf[100];
|
||||
|
||||
snprintf(buf, 100, "%s", "utf-8");
|
||||
snprintf(buf, 20, "%s", name);
|
||||
stream = PySys_GetObject(buf);
|
||||
|
||||
stream = PySys_GetObject(name);
|
||||
snprintf(buf, 20, "%s", "utf-8");
|
||||
snprintf(buf+21, 30, "%s", errors);
|
||||
|
||||
if (!PyFile_SetEncodingAndErrors(stream, buf, errors))
|
||||
if (!PyFile_SetEncodingAndErrors(stream, buf, buf+21))
|
||||
exit(report_python_error("Failed to set stream encoding", 1));
|
||||
|
||||
free(buf);
|
||||
|
||||
}
|
||||
|
||||
@ -187,10 +163,9 @@ void setup_streams() {
|
||||
|
||||
void initialize_interpreter(int argc, char **argv, char *outr, char *errr,
|
||||
const char *basename, const char *module, const char *function) {
|
||||
char *path;
|
||||
char *path, *encoding, *p;
|
||||
|
||||
get_paths();
|
||||
init_env();
|
||||
|
||||
path = (char*)calloc(3*PATH_MAX, sizeof(char));
|
||||
if (!path) OOM;
|
||||
@ -213,6 +188,17 @@ void initialize_interpreter(int argc, char **argv, char *outr, char *errr,
|
||||
|
||||
//printf("Path before Py_Initialize(): %s\r\n\n", Py_GetPath());
|
||||
Py_Initialize();
|
||||
if (!Py_FileSystemDefaultEncoding) {
|
||||
encoding = getenv("PYTHONIOENCODING");
|
||||
if (encoding != NULL) {
|
||||
Py_FileSystemDefaultEncoding = strndup(encoding, 20);
|
||||
p = index(Py_FileSystemDefaultEncoding, ':');
|
||||
if (p != NULL) *p = 0;
|
||||
} else
|
||||
Py_FileSystemDefaultEncoding = strndup("UTF-8", 10);
|
||||
}
|
||||
|
||||
|
||||
setup_streams();
|
||||
|
||||
PySys_SetArgv(argc, argv);
|
||||
@ -220,16 +206,21 @@ void initialize_interpreter(int argc, char **argv, char *outr, char *errr,
|
||||
PySys_SetPath(path);
|
||||
//printf("Path set by me: %s\r\n\n", path);
|
||||
PySys_SetObject("gui_app", PyBool_FromLong((long)GUI_APP));
|
||||
PySys_SetObject("app_dir", PyString_FromString(base_dir));
|
||||
|
||||
PySys_SetObject("calibre_basename", PyBytes_FromString(basename));
|
||||
PySys_SetObject("calibre_module", PyBytes_FromString(module));
|
||||
PySys_SetObject("calibre_function", PyBytes_FromString(function));
|
||||
PySys_SetObject("extensions_location", PyBytes_FromString(extensions_dir));
|
||||
PySys_SetObject("resources_location", PyBytes_FromString(resources_dir));
|
||||
PySys_SetObject("executables_location", PyBytes_FromString(base_dir));
|
||||
PySys_SetObject("frozen_path", PyBytes_FromString(base_dir));
|
||||
PySys_SetObject("frozen", Py_True);
|
||||
Py_INCREF(Py_True);
|
||||
|
||||
//if (GUI_APP && outr && errr) {
|
||||
|
||||
if (GUI_APP && outr && errr) {
|
||||
// PySys_SetObject("stdout_redirect", PyUnicode_FromWideChar(outr, wcslen(outr)));
|
||||
// PySys_SetObject("stderr_redirect", PyUnicode_FromWideChar(errr, wcslen(outr)));
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -256,6 +247,8 @@ int execute_python_entrypoint(int argc, char **argv, const char *basename, const
|
||||
|
||||
if (res == NULL)
|
||||
ret = report_python_error("Python function terminated unexpectedly", 1);
|
||||
|
||||
ret = pyobject_to_int(res);
|
||||
}
|
||||
}
|
||||
PyErr_Clear();
|
||||
|
@ -108,8 +108,7 @@ class Win32Freeze(Command, WixMixIn):
|
||||
for f in x[-1]:
|
||||
if f.lower().endswith('.dll'):
|
||||
f = self.j(x[0], f)
|
||||
if 'py2exe' not in f:
|
||||
shutil.copy2(f, self.dll_dir)
|
||||
shutil.copy2(f, self.dll_dir)
|
||||
shutil.copy2(
|
||||
r'C:\Python%(v)s\Lib\site-packages\pywin32_system32\pywintypes%(v)s.dll'
|
||||
% dict(v=self.py_ver), self.dll_dir)
|
||||
@ -118,7 +117,7 @@ class Win32Freeze(Command, WixMixIn):
|
||||
ans = []
|
||||
for x in items:
|
||||
ext = os.path.splitext(x)[1]
|
||||
if (not ext and (x in ('demos', 'tests') or 'py2exe' in x)) or \
|
||||
if (not ext and (x in ('demos', 'tests'))) or \
|
||||
(ext in ('.dll', '.chm', '.htm', '.txt')):
|
||||
ans.append(x)
|
||||
return ans
|
||||
|
@ -21,6 +21,8 @@ This is where all dependencies will be installed.
|
||||
|
||||
Add C:\Python27\Scripts and C:\Python27 to PATH
|
||||
|
||||
Edit mimetypes.py in C:\Python27\Lib and set _winreg = None to prevent reading of mimetypes from the windows registry
|
||||
|
||||
Install setuptools from http://pypi.python.org/pypi/setuptools
|
||||
If there are no windows binaries already compiled for the version of python you are using then download the source and run the following command in the folder where the source has been unpacked::
|
||||
|
||||
@ -32,6 +34,15 @@ Run the following command to install python dependencies::
|
||||
|
||||
Install BeautifulSoup 3.0.x manually into site-packages (3.1.x parses broken HTML very poorly)
|
||||
|
||||
Install pywin32 and edit win32com\__init__.py setting _frozen = True and
|
||||
__gen_path__ to a temp dir (otherwise it tries to set it to a dir in the install tree which leads to permission errors)
|
||||
Also edit win32com\client\gencache.py and change the except IOError on line 57 to catch all exceptions.
|
||||
|
||||
SQLite
|
||||
---------
|
||||
|
||||
Put sqlite3*.h from the sqlite windows amlgamation in ~/sw/include
|
||||
|
||||
Qt
|
||||
--------
|
||||
|
||||
@ -60,7 +71,11 @@ Compiling instructions::
|
||||
Python Imaging Library
|
||||
------------------------
|
||||
|
||||
Install as normal using provided installer.
|
||||
Install as normal using installer at http://www.lfd.uci.edu/~gohlke/pythonlibs/
|
||||
|
||||
Test it on the target system with
|
||||
|
||||
calibre-debug -c "import _imaging, _imagingmath, _imagingft, _imagingcms"
|
||||
|
||||
Libunrar
|
||||
----------
|
||||
|
@ -632,6 +632,10 @@ def main(outfile, args=sys.argv[1:]):
|
||||
except tokenize.TokenError, e:
|
||||
print >> sys.stderr, '%s: %s, line %d, column %d' % (
|
||||
e[0], filename, e[1][0], e[1][1])
|
||||
except IndentationError, e:
|
||||
print >> sys.stderr, '%s: %s, line %s, column %s' % (
|
||||
e[0], filename, e.lineno, e[1][1])
|
||||
|
||||
finally:
|
||||
if closep:
|
||||
fp.close()
|
||||
|
@ -48,6 +48,13 @@ mimetypes.add_type('application/x-cbz', '.cbz')
|
||||
mimetypes.add_type('application/x-cbr', '.cbr')
|
||||
mimetypes.add_type('application/x-koboreader-ebook', '.kobo')
|
||||
mimetypes.add_type('image/wmf', '.wmf')
|
||||
mimetypes.add_type('image/jpeg', '.jpg')
|
||||
mimetypes.add_type('image/jpeg', '.jpeg')
|
||||
mimetypes.add_type('image/png', '.png')
|
||||
mimetypes.add_type('image/gif', '.gif')
|
||||
mimetypes.add_type('image/bmp', '.bmp')
|
||||
mimetypes.add_type('image/svg+xml', '.svg')
|
||||
|
||||
guess_type = mimetypes.guess_type
|
||||
import cssutils
|
||||
cssutils.log.setLevel(logging.WARN)
|
||||
@ -362,6 +369,8 @@ def walk(dir):
|
||||
def strftime(fmt, t=None):
|
||||
''' A version of strftime that returns unicode strings and tries to handle dates
|
||||
before 1900 '''
|
||||
if not fmt:
|
||||
return u''
|
||||
if t is None:
|
||||
t = time.localtime()
|
||||
if hasattr(t, 'timetuple'):
|
||||
@ -378,7 +387,8 @@ def strftime(fmt, t=None):
|
||||
if isinstance(fmt, unicode):
|
||||
fmt = fmt.encode('mbcs')
|
||||
ans = plugins['winutil'][0].strftime(fmt, t)
|
||||
ans = time.strftime(fmt, t).decode(preferred_encoding, 'replace')
|
||||
else:
|
||||
ans = time.strftime(fmt, t).decode(preferred_encoding, 'replace')
|
||||
if early_year:
|
||||
ans = ans.replace('_early year hack##', str(orig_year))
|
||||
return ans
|
||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
__appname__ = 'calibre'
|
||||
__version__ = '0.7.29'
|
||||
__version__ = '0.7.31'
|
||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||
|
||||
import re
|
||||
|
@ -370,6 +370,15 @@ class InterfaceActionBase(Plugin): # {{{
|
||||
can_be_disabled = False
|
||||
|
||||
actual_plugin = None
|
||||
|
||||
def load_actual_plugin(self, gui):
|
||||
'''
|
||||
This method must return the actual interface action plugin object.
|
||||
'''
|
||||
mod, cls = self.actual_plugin.split(':')
|
||||
return getattr(__import__(mod, fromlist=['1'], level=0), cls)(gui,
|
||||
self.site_customization)
|
||||
|
||||
# }}}
|
||||
|
||||
class PreferencesPlugin(Plugin): # {{{
|
||||
|
@ -457,7 +457,7 @@ from calibre.devices.blackberry.driver import BLACKBERRY
|
||||
from calibre.devices.cybook.driver import CYBOOK, ORIZON
|
||||
from calibre.devices.eb600.driver import EB600, COOL_ER, SHINEBOOK, \
|
||||
POCKETBOOK360, GER2, ITALICA, ECLICTO, DBOOK, INVESBOOK, \
|
||||
BOOQ, ELONEX, POCKETBOOK301, MENTOR
|
||||
BOOQ, ELONEX, POCKETBOOK301, MENTOR, POCKETBOOK602
|
||||
from calibre.devices.iliad.driver import ILIAD
|
||||
from calibre.devices.irexdr.driver import IREXDR1000, IREXDR800
|
||||
from calibre.devices.jetbook.driver import JETBOOK, MIBUK, JETBOOK_MINI
|
||||
@ -476,7 +476,7 @@ from calibre.devices.teclast.driver import TECLAST_K3, NEWSMY, IPAPYRUS, \
|
||||
SOVOS, PICO
|
||||
from calibre.devices.sne.driver import SNE
|
||||
from calibre.devices.misc import PALMPRE, AVANT, SWEEX, PDNOVEL, KOGAN, \
|
||||
GEMEI, VELOCITYMICRO, PDNOVEL_KOBO, Q600
|
||||
GEMEI, VELOCITYMICRO, PDNOVEL_KOBO, Q600, LUMIREAD
|
||||
from calibre.devices.folder_device.driver import FOLDER_DEVICE_FOR_CONFIG
|
||||
from calibre.devices.kobo.driver import KOBO
|
||||
|
||||
@ -547,6 +547,7 @@ plugins += [
|
||||
SHINEBOOK,
|
||||
POCKETBOOK360,
|
||||
POCKETBOOK301,
|
||||
POCKETBOOK602,
|
||||
KINDLE,
|
||||
KINDLE2,
|
||||
KINDLE_DX,
|
||||
@ -599,6 +600,7 @@ plugins += [
|
||||
GEMEI,
|
||||
VELOCITYMICRO,
|
||||
PDNOVEL_KOBO,
|
||||
LUMIREAD,
|
||||
ITUNES,
|
||||
]
|
||||
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
|
||||
|
@ -683,8 +683,8 @@ class NookColorOutput(NookOutput):
|
||||
short_name = 'nook_color'
|
||||
description = _('This profile is intended for the B&N Nook Color.')
|
||||
|
||||
screen_size = (600, 980)
|
||||
comic_screen_size = (584, 980)
|
||||
screen_size = (600, 900)
|
||||
comic_screen_size = (594, 900)
|
||||
dpi = 169
|
||||
|
||||
class BambookOutput(OutputProfile):
|
||||
|
@ -227,4 +227,22 @@ class POCKETBOOK301(USBMS):
|
||||
PRODUCT_ID = [0x301]
|
||||
BCD = [0x132]
|
||||
|
||||
class POCKETBOOK602(USBMS):
|
||||
|
||||
name = 'PocketBook Pro 602 Device Interface'
|
||||
description = _('Communicate with the PocketBook 602 reader.')
|
||||
author = 'Kovid Goyal'
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
FORMATS = ['epub', 'fb2', 'prc', 'mobi', 'pdf', 'djvu', 'rtf', 'chm',
|
||||
'doc', 'tcr', 'txt']
|
||||
|
||||
EBOOK_DIR_MAIN = 'books'
|
||||
SUPPORTS_SUB_DIRS = True
|
||||
|
||||
VENDOR_ID = [0x0525]
|
||||
PRODUCT_ID = [0xa4a5]
|
||||
BCD = [0x0324]
|
||||
|
||||
VENDOR_NAME = ''
|
||||
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'PB602'
|
||||
|
||||
|
@ -25,6 +25,8 @@ class KOBO(USBMS):
|
||||
version = (1, 0, 7)
|
||||
|
||||
dbversion = 0
|
||||
fwversion = 0
|
||||
has_kepubs = False
|
||||
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
|
||||
@ -75,6 +77,14 @@ class KOBO(USBMS):
|
||||
self._card_b_prefix if oncard == 'cardb' \
|
||||
else self._main_prefix
|
||||
|
||||
# Determine the firmware version
|
||||
f = open(self.normalize_path(self._main_prefix + '.kobo/version'), 'r')
|
||||
fwversion = f.readline().split(',')[2]
|
||||
f.close()
|
||||
if fwversion != '1.0' and fwversion != '1.4':
|
||||
self.has_kepubs = True
|
||||
debug_print('Version of firmware: ', fwversion, 'Has kepubs:', self.has_kepubs)
|
||||
|
||||
self.booklist_class.rebuild_collections = self.rebuild_collections
|
||||
|
||||
# get the metadata cache
|
||||
@ -114,7 +124,7 @@ class KOBO(USBMS):
|
||||
#print "Image name Normalized: " + imagename
|
||||
if imagename is not None:
|
||||
bl[idx].thumbnail = ImageWrapper(imagename)
|
||||
if (ContentType != '6'and self.dbversion < 8) or (self.dbversion >= 8):
|
||||
if (ContentType != '6'and self.has_kepubs == False) or (self.has_kepubs == True):
|
||||
if self.update_metadata_item(bl[idx]):
|
||||
# print 'update_metadata_item returned true'
|
||||
changed = True
|
||||
@ -122,7 +132,7 @@ class KOBO(USBMS):
|
||||
playlist_map[lpath] not in bl[idx].device_collections:
|
||||
bl[idx].device_collections.append(playlist_map[lpath])
|
||||
else:
|
||||
if ContentType == '6' and self.dbversion < 8:
|
||||
if ContentType == '6' and self.has_kepubs == False:
|
||||
book = Book(prefix, lpath, title, authors, mime, date, ContentType, ImageID, size=1048576)
|
||||
else:
|
||||
try:
|
||||
@ -142,7 +152,7 @@ class KOBO(USBMS):
|
||||
traceback.print_exc()
|
||||
return changed
|
||||
|
||||
connection = sqlite.connect(self._main_prefix + '.kobo/KoboReader.sqlite')
|
||||
connection = sqlite.connect(self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite'))
|
||||
cursor = connection.cursor()
|
||||
|
||||
#query = 'select count(distinct volumeId) from volume_shortcovers'
|
||||
@ -210,7 +220,7 @@ class KOBO(USBMS):
|
||||
# 2) volume_shorcover
|
||||
# 2) content
|
||||
|
||||
connection = sqlite.connect(self._main_prefix + '.kobo/KoboReader.sqlite')
|
||||
connection = sqlite.connect(self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite'))
|
||||
cursor = connection.cursor()
|
||||
t = (ContentID,)
|
||||
cursor.execute('select ImageID from content where ContentID = ?', t)
|
||||
@ -352,7 +362,7 @@ class KOBO(USBMS):
|
||||
|
||||
def contentid_from_path(self, path, ContentType):
|
||||
if ContentType == 6:
|
||||
if self.dbversion < 8:
|
||||
if self.has_kepubs == False:
|
||||
ContentID = os.path.splitext(path)[0]
|
||||
# Remove the prefix on the file. it could be either
|
||||
ContentID = ContentID.replace(self._main_prefix, '')
|
||||
@ -403,13 +413,13 @@ class KOBO(USBMS):
|
||||
path = path.replace("file:///mnt/sd/", self._card_a_prefix)
|
||||
# print "SD Card: " + path
|
||||
else:
|
||||
if ContentType == "6" and self.dbversion < 8:
|
||||
if ContentType == "6" and self.has_kepubs == False:
|
||||
# This is a hack as the kobo files do not exist
|
||||
# but the path is required to make a unique id
|
||||
# for calibre's reference
|
||||
path = self._main_prefix + path + '.kobo'
|
||||
# print "Path: " + path
|
||||
elif (ContentType == "6" or ContentType == "10") and self.dbversion >= 8:
|
||||
elif (ContentType == "6" or ContentType == "10") and self.has_kepubs == True:
|
||||
path = self._main_prefix + '.kobo/kepub/' + path
|
||||
# print "Internal: " + path
|
||||
else:
|
||||
@ -476,7 +486,7 @@ class KOBO(USBMS):
|
||||
# Needs to be outside books collection as in the case of removing
|
||||
# the last book from the collection the list of books is empty
|
||||
# and the removal of the last book would not occur
|
||||
connection = sqlite.connect(self._main_prefix + '.kobo/KoboReader.sqlite')
|
||||
connection = sqlite.connect(self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite'))
|
||||
cursor = connection.cursor()
|
||||
|
||||
|
||||
|
@ -174,3 +174,33 @@ class GEMEI(USBMS):
|
||||
EBOOK_DIR_MAIN = 'eBooks'
|
||||
SUPPORTS_SUB_DIRS = True
|
||||
|
||||
class LUMIREAD(USBMS):
|
||||
name = 'Acer Lumiread Device Interface'
|
||||
gui_name = 'Lumiread'
|
||||
description = _('Communicate with the Acer Lumiread')
|
||||
author = 'Kovid Goyal'
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
|
||||
# Ordered list of supported formats
|
||||
FORMATS = ['epub', 'pdf', 'mobi', 'chm', 'txt', 'doc', 'docx', 'rtf']
|
||||
|
||||
VENDOR_ID = [0x1025]
|
||||
PRODUCT_ID = [0x048d]
|
||||
BCD = [0x323]
|
||||
|
||||
EBOOK_DIR_MAIN = EBOOK_DIR_CARD_A = 'books'
|
||||
SUPPORTS_SUB_DIRS = True
|
||||
|
||||
THUMBNAIL_HEIGHT = 200
|
||||
|
||||
def upload_cover(self, path, filename, metadata, filepath):
|
||||
if metadata.thumbnail and metadata.thumbnail[-1]:
|
||||
cfilepath = filepath.replace('/', os.sep)
|
||||
cfilepath = cfilepath.replace(os.sep+'books'+os.sep,
|
||||
os.sep+'covers'+os.sep, 1)
|
||||
pdir = os.path.dirname(cfilepath)
|
||||
if not os.exists(pdir):
|
||||
os.makedirs(pdir)
|
||||
with open(cfilepath+'.jpg', 'wb') as f:
|
||||
f.write(metadata.thumbnail[-1])
|
||||
|
||||
|