Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@member.fsf.org>2009-02-28 04:28:45 (GMT)
committer Aleksey Lim <alsroot@member.fsf.org>2009-03-02 06:32:18 (GMT)
commit5b829c11c4444ecc41fc81919776b7b514187106 (patch)
tree39e0a3b07c8d21660523c877994c1cbc80a65b01
parente8e215f382f762513226c9e88f278da1945567ee (diff)
Add journal publishing
-rw-r--r--Processing/Package_Creator.py234
-rw-r--r--activity.py4
-rw-r--r--library.py46
-rw-r--r--xol.py139
4 files changed, 175 insertions, 248 deletions
diff --git a/Processing/Package_Creator.py b/Processing/Package_Creator.py
deleted file mode 100644
index dad218e..0000000
--- a/Processing/Package_Creator.py
+++ /dev/null
@@ -1,234 +0,0 @@
-# Copyright (C) IBM Corporation 2008
-
-import os, platform, zipfile, shutil, re
-from sugar.activity.activity import get_bundle_path, get_activity_root
-
-from NewtifulSoup import NewtifulStoneSoup as BeautifulStoneSoup
-class Package_Creator:
- """
- @author: Matthew Bailey
-
- This class deals with the creation of content packages, comprised of articles from
- themes, with are zipped up and installed in the relevant OS specific location. From
- here they can be distributed to the consumers
- """
-
- """
- Copy articles from library into new content theme (themename) and package up (filename).
- """
- def __init__(self, articlestocopy, themename, filename, caller=None):
- """
- Grab file's parent directory and create temporary directory structure for content
- """
- self.root = os.path.join(get_activity_root(), 'tmp', 'publish')
- shutil.rmtree(self.root, True)
- os.makedirs(self.root)
-
- self.make_directories(themename)
-
- self.info_file(themename)
- self.index_redirect(themename)
-
- self.dita_management(articlestocopy, themename)
-
- self.copy_stylesheets()
- self.create_bundle(themename, filename)
-
- running_on = platform.system()
- if running_on == "Linux" and "olpc" in platform.platform().lower():
- already_exists = self.copy_to_journal(themename)
- if already_exists == True:
- caller.export_message.set_text('A bundle by that name already exists. Please click "Erase" in the Journal. You can click \'Publish\' again afterwards.')
- elif already_exists == False:
- caller.export_message.set_text('Your bundle has been created and will appear in the Journal. You can also create another.')
- else:
- caller.export_message.set_text('We\'re sorry, but something appears to have gone wrong with bundle creation.')
-
- """
- Remove temporary files
- """
- self.remove_directories(themename)
-
- def copy_stylesheets(self):
- """
- Copies the XSL and CSS stylesheets into the slicecontent folder
- @param themename: the name of the theme that is being exported
- """
- for i in glob(os.path.join(get_bundle_path(), 'Stylesheets', '*.xsl')):
-
- themeloc = themename.replace(" ", "_")
- shutil.copyfile('%s/../Stylesheets/ditastylesheet.xsl' % self.currentdir, '%s/%s/slicecontent/ditastylesheet.xsl' % (IO_Manager().workingDir, themeloc))
- shutil.copyfile('%s/../Stylesheets/mapstylesheet.xsl' % self.currentdir, '%s/%s/slicecontent/mapstylesheet.xsl' % (IO_Manager().workingDir, themeloc))
- shutil.copyfile('%s/../Stylesheets/ditastyle.css' % self.currentdir, '%s/%s/slicecontent/ditastyle.css' % (IO_Manager().workingDir, themeloc))
- shutil.copyfile('%s/../Stylesheets/mapstyle.css' % self.currentdir, '%s/%s/slicecontent/mapstyle.css' % (IO_Manager().workingDir, themeloc))
-
- def create_bundle(self, themename, filename):
- """
- Creates the xol package and writes the files and directories to the zip
- @param themename: the name of the theme that is being exported
- """
- themeloc = themename.replace(" ", "_")
- running_on = platform.system()
- if running_on == "Linux" and "olpc" in platform.platform().lower():
- zip = zipfile.ZipFile('%s/%s.xol' % (IO_Manager().workingDir, themeloc), 'w')
- else:
- zip = zipfile.ZipFile(filename, 'w')
- self.zipdir('%s/library/' % themeloc, zip)
- self.zipdir('%s/slicecontent/' % themeloc, zip)
- zip.write('%s/%s/index.html' % (IO_Manager().workingDir, themeloc), '%s/index.html' % themeloc)
- zip.close()
-
- def copy_to_journal(self, themename):
- """
- Copies the xol package to the journal, which can then be copied to a USB drive, etc. and also makes content visible in the browser
- @param themename: the name of the theme that is being exported
- """
- from sugar.datastore import datastore
- from sugar import activity
-# from sugar.bundle.contentbundle import ContentBundle
- journal_listing = datastore.find({'title':themename, 'mime_type':'application/vnd.olpc-content'})
-# for id in journal_listing[0]:
-# test = ContentBundle('/home/olpc/.sugar/default/data/%s.xol' % id.object_id)
-# test.uninstall()
-# datastore.delete(id.object_id)
- if not journal_listing[0]:
- themeloc = themename.replace(" ", "_")
- journal_entry = datastore.create()
- activityinfo_list = activity.get_registry().find_activity("Browse")
-# for activityinfo in activityinfo_list:
-# if activityinfo.name == "Browse":
-# bid = activityinfo.bundle_id
- journal_entry.set_file_path('%s/%s.xol' % (IO_Manager().workingDir, themeloc))
- journal_entry.metadata['title'] = '%s' % themename
-# journal_entry.metadata['activity'] = bid
-# journal_entry.metadata['uri'] = 'file:///home/olpc/.library_pages/search/bundle_index.html'
- journal_entry.metadata['mime_type'] = 'application/vnd.olpc-content'
- journal_entry.metadata['description'] = 'This is a bundle containing articles on %s.\nTo view these articles, first open '\
- 'the \'Browse\' Activity.\nGo to \'Books\', and select \'%s\'.' % (themename, themename)
- datastore.write(journal_entry)
- journal_entry.destroy()
- return False
- elif journal_listing[0]:
- return True
-
- def dita_management(self, articlestocopy, themename):
- """
- Creates a DITA map, and copies the requested articles and their associated images into the zipped directories
- @param articlestocopy: a list of articles to copy
- @param themename: the name of the theme that is being exported
- """
- newmap = ['<?xml version=\'1.0\' encoding=\'utf-8\'?>',\
- '<!DOCTYPE map PUBLIC "-//IBM//DTD DITA IBM Map//EN" "ibm-map.dtd">',\
- '<?xml-stylesheet type="text/xsl" href="mapstylesheet.xsl"?>',\
- '<map title="%s">' % themename]
-
- current_dita_map = IO_Manager().load_map(themename)
- themeloc = themename.replace(" ", "_")
-
- for articlename in articlestocopy:
- articletitle = articlename
- articleloc = current_dita_map.find('topicref', attrs={"navtitle":articlename})['href']
- article = IO_Manager().load_raw_page(articlename, themename)
- #Inserted line above, because line below no longer works due to filename changes
- #article = self.open_article(articleloc.lower())
- self.articlecontent = BeautifulStoneSoup(article)
- for image in self.articlecontent.findAll('image'):
- imageloc = image['href'].replace("..", IO_Manager().workingDir)
- imagename = os.path.split(imageloc)[-1]
- imagename = imagename.replace("%","")
- shutil.copyfile('%s' % (imageloc), '%s/%s/slicecontent/%s' % (IO_Manager().workingDir, themeloc, imagename))
- image['href'] = imagename
- self.articlecontent.insert(1, '<?xml-stylesheet type="text/xsl" href="ditastylesheet.xsl"?>')
- article = open('%s/%s/slicecontent/%s.dita' % (IO_Manager().workingDir, themeloc, IO_Manager().clean_title(articlename)), 'w')
- article.write(self.articlecontent.prettify())
- newmap.append('\t<topicref href="%s.dita" navtitle="%s">' % (IO_Manager().clean_title(articlename), articletitle))
- newmap.append('\t</topicref>')
- newmap.append('</map>')
- ditamap = open('%s/%s/slicecontent/librarymap.ditamap' % (IO_Manager().workingDir, themeloc), 'w')
- ditamap.write("\n".join(newmap))
-
- def index_redirect(self, themename, package_type):
- """
- Creates the redirecting index.html
- @param themename: the name of the theme that is being exported
- @param package_type: the type of package (e.g. 'zip' or 'xol') that is being created
- """
- themeloc = themename.replace(" ", "_")
- if package_type == 'xol':
- redirect_loc = '/home/olpc/Library/%s/slicecontent/librarymap.ditamap' % themeloc
- elif package_type == 'zip':
- redirect_loc = 'slicecontent/librarymap.ditamap'
- html = ['<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">',\
- '<html>',\
- '<head>',\
- '<title>Redirecting to index</title>',\
- '<meta http-equiv="REFRESH" content="0;url=%s">' % redirect_loc,\
- '</head>',\
- '<body>',\
- '</body>',\
- '</html>']
-
- htmlfile = open('%s/%s/index.html' % (IO_Manager().workingDir, themeloc), 'w')
- htmlfile.write("\n".join(html))
-
- def info_file(self, themename):
- """
- Creates the library.info file
- @param themename: the name of the theme that is being exported
- """
- themeloc = themename.replace(" ", "_")
- libraryfile = ['[Library]',\
- 'name = %s' % themeloc,\
- 'global_name = info.slice.%s' % themename.lower(),\
- 'long_name = %s' % themename,\
- 'library_version = 1',\
- 'host_version = 1',\
- 'l10n = false',\
- 'locale = en',\
- 'category = books',\
- 'subcategory = slice',\
- 'icon = book.png',\
- 'activity = Web',\
- 'activity_start = index.html']
-
- infofile = open('%s/%s/library/library.info' % (IO_Manager().workingDir, themeloc), 'w')
- infofile.write("\n".join(libraryfile))
-
- def make_directories(self, themename):
- """
- Creates the directories that will be zipped
- @param themename: the name of the theme that is being exported
- """
- themename = themename.replace(" ", "_")
- if os.path.exists("%s/%s" % (IO_Manager().workingDir, themename)):
- shutil.rmtree("%s/%s" % (IO_Manager().workingDir, themename))
- os.mkdir('%s/%s' % (IO_Manager().workingDir, themename))
- os.mkdir('%s/%s/library' % (IO_Manager().workingDir, themename))
- os.mkdir('%s/%s/slicecontent' % (IO_Manager().workingDir, themename))
-
- def open_article(self, articleloc):
- """
- Opens the relevant DITA file and returns it as a string
- @param articleloc: the location of the DITA file to be opened
- @return: a string containing the contents of the DITA file
- """
- file = open('%s' % (articleloc), 'r').read()
- return file
-
- def remove_directories(self, themename):
- """
- Removes the directories created on the filesystem for the zip
- @param themename: the name of the theme that is being exported
- """
- themename = themename.replace(" ", "_")
- shutil.rmtree("%s/%s" % (IO_Manager().workingDir, themename))
-
- def zipdir(self, path, zip):
- """
- Writes directories and their contents to the zip
- @param path: the path of the directory that is to be zipped
- @param zip: the variable name of the zip that is to be written to
- """
- fullpath = '%s/%s' % (IO_Manager().workingDir, path)
- for each in os.listdir(fullpath):
- zip.write(fullpath + each, path + each)
diff --git a/activity.py b/activity.py
index 3923e4b..4400bb3 100644
--- a/activity.py
+++ b/activity.py
@@ -52,7 +52,7 @@ class InfoslicerActivity(SharedActivity):
self.edit = edit.View()
self.edit_bar = edit.Toolbar(self.edit)
- self.library = library.View(self._set_edit_sensitive)
+ self.library = library.View(self)
library_bar = library.Toolbar(self.library)
toolbox = ActivityToolbox(self)
@@ -70,7 +70,7 @@ class InfoslicerActivity(SharedActivity):
toolbox.set_current_toolbar(1)
self.show_all()
- def _set_edit_sensitive(self, enable):
+ def set_edit_sensitive(self, enable):
self.edit_bar.props.sensitive = enable
self.edit_page = (enable and 1 or 2)
diff --git a/library.py b/library.py
index cd2a875..1100b54 100644
--- a/library.py
+++ b/library.py
@@ -22,23 +22,25 @@ from sugar.graphics.toggletoolbutton import ToggleToolButton
from sugar.activity.activity import ActivityToolbox
from sugar.graphics.toolcombobox import ToolComboBox
from sugar.graphics.icon import Icon
+from sugar.graphics.alert import ConfirmationAlert
+from sugar.datastore import datastore
import sugar.graphics.style as style
-import net
-import book
from GUI_Components.Compound_Widgets.toolbar import WidgetItem
from GUI_Components.Compound_Widgets.bookview import BookView
from GUI_Components.Compound_Widgets.Reading_View import Reading_View
-from Processing.Package_Creator import Package_Creator
+import book
+import xol
+import net
class View(gtk.EventBox):
def sync(self):
self.wiki.sync()
self.custom.sync()
- def __init__(self, set_edit_sensitive):
+ def __init__(self, activity):
gtk.EventBox.__init__(self)
- self._set_edit_sensitive = set_edit_sensitive
+ self.activity = activity
# books
@@ -124,7 +126,7 @@ class View(gtk.EventBox):
book.custom.connect('article-deleted', self._article_deleted_cb, custom)
self._edit_sensitive = 0
- self._set_edit_sensitive(False)
+ self.activity.set_edit_sensitive(False)
if not book.wiki.article:
wiki.set_current_page(1)
@@ -144,19 +146,20 @@ class View(gtk.EventBox):
self._edit_sensitive += 1
if self._edit_sensitive == 2:
- self._set_edit_sensitive(True)
+ self.activity.set_edit_sensitive(True)
def _article_deleted_cb(self, abook, article, notebook):
if abook.map:
return
notebook.set_current_page(1)
self._edit_sensitive -= 1
- self._set_edit_sensitive(False)
+ self.activity.set_edit_sensitive(False)
class Toolbar(gtk.Toolbar):
def __init__(self, library):
gtk.Toolbar.__init__(self)
self.library = library
+ self.activity = library.activity
self.wikimenu = ToolComboBox(label_text=_('Get article from:'))
for i in sorted(WIKI.keys()):
@@ -185,16 +188,35 @@ class Toolbar(gtk.Toolbar):
separator.show()
publish = ToolButton('filesave', tooltip=_('Publish selected articles'))
- publish.connect("clicked", self._publish_clicked_cb)
+ publish.connect("clicked", self._publish_clicked_cb, False)
self.insert(publish, -1)
publish.show()
self.connect('map', self._map_cb)
- def _publish_clicked_cb(self):
+ def _publish_clicked_cb(self, widget, force):
+ title = self.activity.metadata['title']
+ jobject = datastore.find({'title': title,
+ 'mime_type': 'application/vnd.olpc-content'})[0] or None
+
+ if jobject and not force:
+ alert = ConfirmationAlert(
+ title=_('Overwrite?'),
+ msg=_('A bundle by that name already exists.' \
+ 'Click "OK" to overwrite it.'))
+
+ def response(alert, response_id, self):
+ self.activity.remove_alert(alert)
+ if response_id is gtk.RESPONSE_OK:
+ self._publish_clicked_cb(None, True)
+
+ alert.connect('response', response, self)
+ alert.show_all()
+ self.activity.add_alert(alert)
+ return
+
book.custom.sync()
- Package_Creator(book.custom.article,
- datetime.strftime(datetime.now(), '%F %T'))
+ xol.publish(title, jobject)
def _map_cb(self, widget):
self.searchentry.grab_focus()
diff --git a/xol.py b/xol.py
new file mode 100644
index 0000000..c8231ff
--- /dev/null
+++ b/xol.py
@@ -0,0 +1,139 @@
+# Copyright (C) IBM Corporation 2008
+
+import os
+import zipfile
+import uuid
+from glob import glob
+
+from sugar.activity.activity import get_bundle_path, get_activity_root
+from sugar.datastore import datastore
+from sugar import activity
+
+from Processing.NewtifulSoup import NewtifulStoneSoup as BeautifulStoneSoup
+import book
+
+"""
+@author: Matthew Bailey
+
+This class deals with the creation of content packages, comprised of articles from
+themes, with are zipped up and installed in the relevant OS specific location. From
+here they can be distributed to the consumers
+"""
+def publish(title, jobject):
+ zipfilename = os.path.join(get_activity_root(), 'tmp', 'publish.xol')
+ zip = zipfile.ZipFile(zipfilename, 'w')
+
+ uid = str(uuid.uuid1())
+
+ for i in glob(os.path.join(get_bundle_path(), 'Stylesheets', '*')):
+ zip.write(i, os.path.join(uid, 'slicecontent', os.path.basename(i)))
+
+ info_file(zip, uid, title)
+ index_redirect(zip, uid)
+ dita_management(zip, uid, title)
+
+ zip.close()
+
+ if not jobject:
+ jobject = datastore.create()
+ jobject.metadata['title'] = title
+ jobject.metadata['mime_type'] = 'application/vnd.olpc-content'
+ jobject.metadata['description'] = \
+ 'This is a bundle containing articles on %s.\n' \
+ 'To view these articles, open the \'Browse\' Activity.\n' \
+ 'Go to \'Books\', and select \'%s\'.' % (title, title)
+
+ jobject.set_file_path(zipfilename)
+ datastore.write(jobject)
+ jobject.destroy()
+
+def dita_management(zip, uid, title):
+ """
+ Creates a DITA map, and copies the requested articles and their associated images into the zipped directories
+ """
+ map = [ '<?xml version=\'1.0\' encoding=\'utf-8\'?>',\
+ '<!DOCTYPE map PUBLIC "-//IBM//DTD DITA IBM Map//EN" ' \
+ '"ibm-map.dtd">',\
+ '<?xml-stylesheet type="text/xsl" href="mapstylesheet.xsl"?>',\
+ '<map title="%s">' % title ]
+
+ images = {}
+
+ for entry in book.custom.map:
+ if not entry['ready']:
+ continue
+
+ atitle = entry['title']
+ auid = entry['uid']
+
+ content = BeautifulStoneSoup(book.custom._load(auid))
+
+ for image in content.findAll('image'):
+ image_path = image['href'].replace("..", book.wiki.root)
+ image_name = os.path.basename(image_path)
+ image_ext = os.path.splitext(image_name)[1]
+
+ image_num = images.get(image_name, len(images))
+ images[image_name] = image_num
+ image_name = ('%08d%s' % (image_num, image_ext)).encode('CP437')
+
+ zip.write(image_path, os.path.join(uid, 'slicecontent', image_name))
+ image['href'] = image_name
+
+ content.insert(1, '<?xml-stylesheet type="text/xsl" ' \
+ 'href="ditastylesheet.xsl"?>')
+ zipstr(zip, os.path.join(uid, 'slicecontent', '%s.dita' % auid),
+ content.prettify())
+
+ map.append('<topicref href="%s.dita" navtitle="%s">' % (auid, atitle))
+ map.append('</topicref>')
+
+ map.append('</map>')
+ zipstr(zip, os.path.join(uid, 'slicecontent', 'librarymap.ditamap'),
+ "\n".join(map))
+
+def index_redirect(zip, uid):
+ """
+ Creates the redirecting index.html
+ """
+ redirect_loc = 'slicecontent/librarymap.ditamap'
+
+ html = ['<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">',\
+ '<html>',\
+ '<head>',\
+ '<title>Redirecting to index</title>',\
+ '<meta http-equiv="REFRESH" content="0;url=%s">' % redirect_loc,\
+ '</head>',\
+ '<body>',\
+ '</body>',\
+ '</html>']
+
+ zipstr(zip, os.path.join(uid, 'index.html'), "\n".join(html))
+
+def info_file(zip, uid, title):
+ """
+ Creates the library.info file
+ """
+ libraryfile = ['[Library]',\
+ 'name = %s' % uid,\
+ 'global_name = info.slice.%s' % uid,\
+ 'long_name = %s' % title,\
+ 'library_version = 1',\
+ 'host_version = 1',\
+ 'l10n = false',\
+ 'locale = en',\
+ 'category = books',\
+ 'subcategory = slice',\
+ 'icon = book.png',\
+ 'activity = Web',\
+ 'activity_start = index.html']
+
+ zipstr(zip, os.path.join(uid, 'library', 'library.info'),
+ "\n".join(libraryfile))
+
+# XXX setup mode_t for files written by writestr()
+def zipstr(zip, arcname, str):
+ import copy
+ zipinfo = copy.copy(zip.infolist()[0])
+ zipinfo.filename = arcname
+ zip.writestr(zipinfo, str)