
The bundle API is a bit confusing and inconsistent. Fix up the ActivityBundle and ContentBundle classes to be more consistent and to work with the ongoing improvements being made in bundleregistry.
235 lines
7.4 KiB
Python
235 lines
7.4 KiB
Python
# Copyright (C) 2007, Red Hat, Inc.
|
|
# Copyright (C) 2009 Aleksey Lim
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2 of the License, or (at your option) any later version.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with this library; if not, write to the
|
|
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
# Boston, MA 02111-1307, USA.
|
|
|
|
"""Sugar content bundles
|
|
|
|
UNSTABLE.
|
|
"""
|
|
|
|
from ConfigParser import ConfigParser
|
|
import os
|
|
import urllib
|
|
|
|
from sugar3 import env
|
|
from sugar3.bundle.bundle import Bundle, MalformedBundleException
|
|
|
|
from sugar3.bundle.bundleversion import NormalizedVersion
|
|
from sugar3.bundle.bundleversion import InvalidVersionError
|
|
|
|
|
|
class ContentBundle(Bundle):
|
|
"""A Sugar content bundle
|
|
|
|
See http://wiki.laptop.org/go/Content_bundles for details
|
|
"""
|
|
|
|
MIME_TYPE = 'application/vnd.olpc-content'
|
|
|
|
_zipped_extension = '.xol'
|
|
_unzipped_extension = None
|
|
_infodir = 'library'
|
|
|
|
def __init__(self, path):
|
|
Bundle.__init__(self, path)
|
|
|
|
self._locale = None
|
|
self._l10n = None
|
|
self._category = None
|
|
self._name = None
|
|
self._subcategory = None
|
|
self._category_class = None
|
|
self._category_icon = None
|
|
self._library_version = '0'
|
|
self._bundle_class = None
|
|
self._activity_start = None
|
|
self._global_name = None
|
|
|
|
info_file = self.get_file('library/library.info')
|
|
if info_file is None:
|
|
raise MalformedBundleException('No library.info file')
|
|
self._parse_info(info_file)
|
|
|
|
if (self.get_file('index.html') is None and
|
|
self.get_file('library/library.xml') is None):
|
|
raise MalformedBundleException(
|
|
'Content bundle %s has neither index.html nor library.xml' %
|
|
self._path)
|
|
|
|
def _parse_info(self, info_file):
|
|
cp = ConfigParser()
|
|
cp.readfp(info_file)
|
|
|
|
section = 'Library'
|
|
|
|
if cp.has_option(section, 'name'):
|
|
self._name = cp.get(section, 'name')
|
|
else:
|
|
raise MalformedBundleException(
|
|
'Content bundle %s does not specify a name' % self._path)
|
|
|
|
if cp.has_option(section, 'library_version'):
|
|
version = cp.get(section, 'library_version')
|
|
try:
|
|
NormalizedVersion(version)
|
|
except InvalidVersionError:
|
|
raise MalformedBundleException(
|
|
'Content bundle %s has invalid version number %s' %
|
|
(self._path, version))
|
|
self._library_version = version
|
|
|
|
if cp.has_option(section, 'l10n'):
|
|
l10n = cp.get(section, 'l10n')
|
|
if l10n == 'true':
|
|
self._l10n = True
|
|
elif l10n == 'false':
|
|
self._l10n = False
|
|
else:
|
|
raise MalformedBundleException(
|
|
'Content bundle %s has invalid l10n key %r' %
|
|
(self._path, l10n))
|
|
else:
|
|
raise MalformedBundleException(
|
|
'Content bundle %s does not specify if it is localized' %
|
|
self._path)
|
|
|
|
if cp.has_option(section, 'locale'):
|
|
self._locale = cp.get(section, 'locale')
|
|
else:
|
|
raise MalformedBundleException(
|
|
'Content bundle %s does not specify a locale' % self._path)
|
|
|
|
if cp.has_option(section, 'category'):
|
|
self._category = cp.get(section, 'category')
|
|
else:
|
|
raise MalformedBundleException(
|
|
'Content bundle %s does not specify a category' % self._path)
|
|
|
|
if cp.has_option(section, 'global_name'):
|
|
self._global_name = cp.get(section, 'global_name')
|
|
else:
|
|
self._global_name = None
|
|
|
|
if cp.has_option(section, 'category_icon'):
|
|
self._category_icon = cp.get(section, 'category_icon')
|
|
else:
|
|
self._category_icon = None
|
|
|
|
if cp.has_option(section, 'category_class'):
|
|
self._category_class = cp.get(section, 'category_class')
|
|
else:
|
|
self._category_class = None
|
|
|
|
if cp.has_option(section, 'subcategory'):
|
|
self._subcategory = cp.get(section, 'subcategory')
|
|
else:
|
|
self._subcategory = None
|
|
|
|
if cp.has_option(section, 'bundle_class'):
|
|
self._bundle_class = cp.get(section, 'bundle_class')
|
|
else:
|
|
self._bundle_class = None
|
|
|
|
if cp.has_option(section, 'activity_start'):
|
|
self._activity_start = cp.get(section, 'activity_start')
|
|
else:
|
|
self._activity_start = 'index.html'
|
|
|
|
if self._bundle_class is None and self._global_name is None:
|
|
raise MalformedBundleException(
|
|
'Content bundle %s must specify either global_name or '
|
|
'bundle_class' % self._path)
|
|
|
|
def get_name(self):
|
|
return self._name
|
|
|
|
def get_library_version(self):
|
|
return self._library_version
|
|
|
|
def get_l10n(self):
|
|
return self._l10n
|
|
|
|
def get_locale(self):
|
|
return self._locale
|
|
|
|
def get_category(self):
|
|
return self._category
|
|
|
|
def get_category_icon(self):
|
|
return self._category_icon
|
|
|
|
def get_category_class(self):
|
|
return self._category_class
|
|
|
|
def get_subcategory(self):
|
|
return self._subcategory
|
|
|
|
def get_bundle_class(self):
|
|
return self._bundle_class
|
|
|
|
def get_activity_start(self):
|
|
return self._activity_start
|
|
|
|
def get_icon(self):
|
|
# To be implemented later
|
|
return None
|
|
|
|
def _run_indexer(self):
|
|
xdg_data_dirs = os.getenv('XDG_DATA_DIRS',
|
|
'/usr/local/share/:/usr/share/')
|
|
for path in xdg_data_dirs.split(':'):
|
|
indexer = os.path.join(path, 'library-common', 'make_index.py')
|
|
if os.path.exists(indexer):
|
|
os.spawnlp(os.P_WAIT, 'python', 'python', indexer)
|
|
|
|
def get_root_dir(self):
|
|
return os.path.join(env.get_user_library_path(), self._zip_root_dir)
|
|
|
|
def get_start_path(self):
|
|
return os.path.join(self.get_root_dir(), self._activity_start)
|
|
|
|
def get_start_uri(self):
|
|
return 'file://' + urllib.pathname2url(self.get_start_path())
|
|
|
|
def get_bundle_id(self):
|
|
# TODO treat ContentBundle in special way
|
|
# needs rethinking while fixing ContentBundle support
|
|
if self._bundle_class is not None:
|
|
return self._bundle_class
|
|
else:
|
|
return self._global_name
|
|
|
|
def get_activity_version(self):
|
|
# TODO treat ContentBundle in special way
|
|
# needs rethinking while fixing ContentBundle support
|
|
return self._library_version
|
|
|
|
def install(self):
|
|
install_path = env.get_user_library_path()
|
|
self._unzip(install_path)
|
|
self._run_indexer()
|
|
return self.get_root_dir()
|
|
|
|
def uninstall(self, force=False, delete_profile=False):
|
|
install_dir = self._path
|
|
self._uninstall(install_dir)
|
|
self._run_indexer()
|
|
|
|
def is_user_activity(self):
|
|
# All content bundles are installed in user storage
|
|
return True
|