diff options
author | Sascha Silbe <sascha-pgp@silbe.org> | 2010-07-04 20:02:16 (GMT) |
---|---|---|
committer | Sascha Silbe <sascha-pgp@silbe.org> | 2010-07-04 20:02:16 (GMT) |
commit | 6c2cd2c341738b28b10449df2faa622cd32b6b04 (patch) | |
tree | 23e448d84cb9caf17104cd4a510825d33308af3d | |
parent | 2141069a3298861305a0145e059fc99c61039ab1 (diff) | |
parent | d6d98ece1fb258d5ad4fea70d2b6a62db5040c5f (diff) |
Merge commit 'refs/top-bases/t/backup' into t/backup
-rw-r--r-- | src/jarabe/journal/journalentrybundle.py | 139 | ||||
-rw-r--r-- | src/jarabe/model/bundleregistry.py | 6 |
2 files changed, 97 insertions, 48 deletions
diff --git a/src/jarabe/journal/journalentrybundle.py b/src/jarabe/journal/journalentrybundle.py index 41777c7..a33bb59 100644 --- a/src/jarabe/journal/journalentrybundle.py +++ b/src/jarabe/journal/journalentrybundle.py @@ -14,24 +14,30 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import logging import os import tempfile -import shutil -import simplejson import dbus -from sugar.bundle.bundle import Bundle, MalformedBundleException +try: + import json +except ImportError: + import simplejson as json +from sugar.bundle.bundle import Bundle, MalformedBundleException from jarabe.journal import model + class JournalEntryBundle(Bundle): """A Journal entry bundle See http://wiki.laptop.org/go/Journal_entry_bundles for details """ + # TODO: migrate to SL wiki MIME_TYPE = 'application/vnd.olpc-journal-entry' + _METADATA_JSON_NAME = '_metadata.json' _zipped_extension = '.xoj' _unzipped_extension = None @@ -40,55 +46,98 @@ class JournalEntryBundle(Bundle): def __init__(self, path): Bundle.__init__(self, path) - def install(self, uid=''): - if os.environ.has_key('SUGAR_ACTIVITY_ROOT'): - install_dir = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], - 'data') - else: - install_dir = tempfile.gettempdir() - bundle_dir = os.path.join(install_dir, self._zip_root_dir) - temp_uid = self._zip_root_dir - self._unzip(install_dir) - try: - metadata = self._read_metadata(bundle_dir) - metadata['uid'] = uid - - preview = self._read_preview(temp_uid, bundle_dir) - if preview is not None: - metadata['preview'] = dbus.ByteArray(preview) - - file_path = os.path.join(bundle_dir, temp_uid) - model.write(metadata, file_path) - finally: - shutil.rmtree(bundle_dir, ignore_errors=True) + def _check_zip_bundle(self): + # potentially expensive, but avoids trouble during unpacking + if self._zip_file.testzip() is not None: + raise MalformedBundleException('Corrupt zip file') + + file_names = self._zip_file.namelist() + if len(file_names) == 0: + raise MalformedBundleException('Empty zip file') + + metadata_seen = False + for name in file_names: + for part in name.split('/'): + if part.startswith('.'): + raise MalformedBundleException( + 'Path component starts with dot: %r', name) + + if name.split('/')[-1] == self._METADATA_JSON_NAME: + metadata_seen = True + + if not metadata_seen: + raise MalformedBundleException('No metadata file found') + + def install(self): + for object_id, file_paths in self._get_directories().items(): + if len(object_id) < 36: + logging.warning('Ignoring unknown directory %r', object_id) + continue + + if self._METADATA_JSON_NAME not in file_paths: + logging.warning('Ignoring directory %r without %s', + object_id, self._METADATA_JSON_NAME) + continue + + try: + self._install_entry(object_id, file_paths) + except Exception: + logging.exception('Error installing Journal entry %r:', + object_id) + + def _install_entry(self, object_id, file_paths): + file_paths.remove(self._METADATA_JSON_NAME) + metadata = self._read_metadata(object_id) + + data_file_name = '' + if object_id in file_paths: + file_paths.remove(object_id) + data_file_name = self._read_data(object_id) + + for path in file_paths: + components = path.split('/') + if len(components) != 2 or components[1] != object_id: + logging.warning('Ignoring unknown file %r', path) + + name = components[0] + value = self._zip_file.read(os.path.join(object_id, path)) + metadata[name] = dbus.ByteArray(value) + + model.write(metadata, data_file_name, transfer_ownership=True) def get_bundle_id(self): return None - def _read_metadata(self, bundle_dir): - metadata_path = os.path.join(bundle_dir, '_metadata.json') - if not os.path.exists(metadata_path): - raise MalformedBundleException( - 'Bundle must contain the file "_metadata.json"') - f = open(metadata_path, 'r') + def _read_data(self, object_id): + data_fd, data_file_name = tempfile.mkstemp(prefix='JEB') + data_file = os.fdopen(data_fd, 'w') try: - json_data = f.read() + # TODO: handle large files better (i.e. use external tool) + # TODO: predict disk-full + data_file.write(self._zip_file.read( + os.path.join(object_id, object_id))) + return data_file_name finally: - f.close() - return simplejson.loads(json_data) - - def _read_preview(self, uid, bundle_dir): - preview_path = os.path.join(bundle_dir, 'preview', uid) - if not os.path.exists(preview_path): - return '' - f = open(preview_path, 'r') - try: - preview_data = f.read() - finally: - f.close() - return preview_data + data_file.close() + + def _read_metadata(self, object_id): + metadata_path = os.path.join(object_id, self._METADATA_JSON_NAME) + json_data = self._zip_file.read(metadata_path) + return json.loads(json_data) + + def _get_directories(self): + """Return the names of all top-level directories and their contents. + """ + contents = {} + for path in self._zip_file.namelist(): + if path.endswith('/'): + continue + + directory, file_name = path.lstrip('/').split('/', 1) + contents.setdefault(directory, []).append(file_name) + + return contents def is_installed(self): # These bundles can be reinstalled as many times as desired. return False - diff --git a/src/jarabe/model/bundleregistry.py b/src/jarabe/model/bundleregistry.py index 86a2738..f4c7275 100644 --- a/src/jarabe/model/bundleregistry.py +++ b/src/jarabe/model/bundleregistry.py @@ -164,7 +164,7 @@ class BundleRegistry(gobject.GObject): if bundle.get_bundle_id() == bundle_id: return bundle return None - + def __iter__(self): return self._bundles.__iter__() @@ -364,7 +364,7 @@ class BundleRegistry(gobject.GObject): install_dir = env.get_user_activities_path() if isinstance(bundle, JournalEntryBundle): - install_path = bundle.install(uid) + install_path = bundle.install() else: install_path = bundle.install(install_dir) @@ -376,7 +376,7 @@ class BundleRegistry(gobject.GObject): elif not self.add_bundle(install_path): raise RegistrationException - def uninstall(self, bundle, force=False): + def uninstall(self, bundle, force=False): # TODO treat ContentBundle in special way # needs rethinking while fixing ContentBundle support if isinstance(bundle, ContentBundle) or \ |