[Sugar-devel] [PATCH sugar] Convert Journal entries that have been saved to a storage device pre 0.84
Simon Schampijer
simon at schampijer.de
Tue Feb 22 11:27:59 EST 2011
Converts the entries to the new format [1] when the device is plugged
into the machine.
[1] http://wiki.sugarlabs.org/go/Features/Journal_Entry_Sharing
---
src/jarabe/journal/volumestoolbar.py | 132 +++++++++++++++++++++++++++++++++-
1 files changed, 131 insertions(+), 1 deletions(-)
diff --git a/src/jarabe/journal/volumestoolbar.py b/src/jarabe/journal/volumestoolbar.py
index 2d842f1..72b5918 100644
--- a/src/jarabe/journal/volumestoolbar.py
+++ b/src/jarabe/journal/volumestoolbar.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2007, One Laptop Per Child
+# Copyright (C) 2007, 2011, One Laptop Per Child
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -23,6 +23,11 @@ import gobject
import gio
import gtk
import gconf
+import cPickle
+import xapian
+import simplejson
+import tempfile
+import shutil
from sugar.graphics.radiotoolbutton import RadioToolButton
from sugar.graphics.palette import Palette
@@ -33,6 +38,126 @@ from jarabe.journal import model
from jarabe.view.palettes import VolumePalette
+_JOURNAL_0_METADATA_DIR = '.olpc.store'
+
+
+def _get_id(document):
+ """Get the ID for the document in the xapian database."""
+ tl = document.termlist()
+ try:
+ term = tl.skip_to('Q').term
+ if len(term) == 0 or term[0] != 'Q':
+ return None
+ return term[1:]
+ except StopIteration:
+ return None
+
+
+def _convert_entries(root):
+ """Convert entries written by the datastore version 0.
+
+ The metadata and the preview will be written using the new
+ scheme for writing Journal entries to removable storage
+ devices.
+
+ - entries that do not have an associated file are not
+ converted.
+ - if an entry has no title we set it to Untitled and rename
+ the file accordingly, taking care of creating a unique
+ filename
+
+ """
+ try:
+ database = xapian.Database(os.path.join(root, _JOURNAL_0_METADATA_DIR,
+ 'index'))
+ except xapian.DatabaseError:
+ logging.exception('Convert DS-0 Journal entries: error reading db: %s',
+ os.path.join(root, _JOURNAL_0_METADATA_DIR, 'index'))
+ return
+
+ metadata_dir_path = os.path.join(root, model.JOURNAL_METADATA_DIR)
+ if not os.path.exists(metadata_dir_path):
+ try:
+ os.mkdir(metadata_dir_path)
+ except EnvironmentError:
+ logging.error('Convert DS-0 Journal entries: '
+ 'error creating the Journal metadata directory.')
+ return
+
+ for posting_item in database.postlist(''):
+ try:
+ document = database.get_document(posting_item.docid)
+ except xapian.DocNotFoundError, e:
+ logging.debug('Convert DS-0 Journal entries: error getting '
+ 'document %s: %s', posting_item.docid, e)
+ continue
+ _convert_entry(root, document)
+
+
+def _convert_entry(root, document):
+ try:
+ metadata_loaded = cPickle.loads(document.get_data())
+ except cPickle.PickleError, e:
+ logging.debug('Convert DS-0 Journal entries: '
+ 'error converting metadata: %s', e)
+ return
+
+ if not ('activity_id' in metadata_loaded and
+ 'mime_type' in metadata_loaded and
+ 'title' in metadata_loaded):
+ return
+
+ metadata = {}
+
+ uid = _get_id(document)
+ if uid is None:
+ return
+
+ for key, value in metadata_loaded.items():
+ metadata[str(key)] = str(value[0])
+
+ if 'uid' not in metadata:
+ metadata['uid'] = uid
+
+ filename = metadata.pop('filename', None)
+ if not filename:
+ return
+ if not os.path.exists(os.path.join(root, filename)):
+ return
+
+ if not metadata.get('title'):
+ metadata['title'] = _('Untitled')
+ fn = model.get_file_name(metadata['title'],
+ metadata['mime_type'])
+ new_filename = model.get_unique_file_name(root, fn)
+ os.rename(os.path.join(root, filename),
+ os.path.join(root, new_filename))
+ filename = new_filename
+
+ preview_path = os.path.join(root, _JOURNAL_0_METADATA_DIR,
+ 'preview', uid)
+ if os.path.exists(preview_path):
+ preview_fname = filename + '.preview'
+ new_preview_path = os.path.join(root,
+ model.JOURNAL_METADATA_DIR,
+ preview_fname)
+ if not os.path.exists(new_preview_path):
+ shutil.copy(preview_path, new_preview_path)
+
+ metadata_fname = filename + '.metadata'
+ metadata_path = os.path.join(root, model.JOURNAL_METADATA_DIR,
+ metadata_fname)
+ if not os.path.exists(metadata_path):
+ (fh, fn) = tempfile.mkstemp(dir=root)
+ os.write(fh, simplejson.dumps(metadata))
+ os.close(fh)
+ os.rename(fn, metadata_path)
+
+ logging.debug('Convert DS-0 Journal entries: entry converted: '
+ 'file=%s metadata=%s',
+ os.path.join(root, filename), metadata)
+
+
class VolumesToolbar(gtk.Toolbar):
__gtype_name__ = 'VolumesToolbar'
@@ -82,6 +207,11 @@ class VolumesToolbar(gtk.Toolbar):
def _add_button(self, mount):
logging.debug('VolumeToolbar._add_button: %r', mount.get_name())
+ if os.path.exists(os.path.join(mount.get_root().get_path(),
+ _JOURNAL_0_METADATA_DIR)):
+ logging.debug('Convert DS-0 Journal entries: starting conversion')
+ gobject.idle_add(_convert_entries, mount.get_root().get_path())
+
button = VolumeButton(mount)
button.props.group = self._volume_buttons[0]
button.connect('toggled', self._button_toggled_cb)
--
1.7.4
More information about the Sugar-devel
mailing list