[Sugar-devel] [PATCH] Add ds2xos conversion script to export journal entries as .xos session dirs.

Michael Stone michael at laptop.org
Sat Jun 26 23:07:42 EDT 2010


This script converts the contents of whatever datastore is accessible on the
current session bus to subdirectories of the current working directory.

The purpose of this conversion is to encode all the data needed to show a nice
journal entry into a wire format that is easy to process with standard
filesystem tools and APIs.

The chosen format consists of one ".xos session dir" per journal entry.

A session dir is a directory:

   * whose name is URL-encoded with spaces encoded as pluses

   * which contains a directory named ".xos":
       * which contains a file called "metadata.json"
       * which, optionally, contains an image named "preview.png"
       * which, optionally, contains an executable called "resume"

   * and which may contain any other files or directories you like

When creating session dirs from pre-existing journal entries:

   * we do our best to come up with human-meaningful and unique names by
     concatenating a few bytes of the journal entry's "activity_id" field onto
     the journal entry's "title" field separated by an underscore,

   * we try to create stand-alone "resume" files and to ensure that all the data
     that we put into such files is shell-quoted, and

   * we try to hard-link any files associated with the journal entry into our
     session dir with names derived from the title and mime-type of the stored
     file.

Signed-off-by: Michael Stone <michael at laptop.org>
---
  datastore/bin/ds2xos |  133 ++++++++++++++++++++++++++++++++++++++++++++++++++
  1 files changed, 133 insertions(+), 0 deletions(-)
  create mode 100755 datastore/bin/ds2xos

diff --git a/datastore/bin/ds2xos b/datastore/bin/ds2xos
new file mode 100755
index 0000000..79565ff
--- /dev/null
+++ b/datastore/bin/ds2xos
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+from __future__ import with_statement, division
+
+import sys, cgitb
+cgitb.enable(format="plain")
+cgitb.handler = sys.excepthook.handle
+
+from pprint import pprint
+from sugar.datastore import datastore as ds
+from os.path import exists, join, splitext
+from os import makedirs, rename, link, chmod
+from commands import mkarg
+from errno import EEXIST
+from urllib import quote_plus
+from jarabe.model.bundleregistry import get_registry
+from sugar import env
+import cjson
+import sugar.mime
+
+def mkdir_p(path):
+    try: makedirs(path)
+    except OSError, e:
+        if e.errno == EEXIST: pass
+        else: raise
+
+def get_bundle(md):
+    return get_registry().get_bundle(str(md['activity']))
+
+def get_command(md, bundle):
+    command = bundle.get_command().split(' ')
+    command.extend(['-b', str(md['activity'])])
+    command.extend(['-a', str(md['activity_id'])])
+
+    if 'object_id' in md and md['object_id'] != "":
+        command.extend(['-o', str(md['object_id'])])
+    if 'uri' in md and md['uri'] != "":
+        command.extend(['-u', str(md['uri'])])
+
+    # if the command is in $BUNDLE_ROOT/bin, execute the absolute path so there
+    # is no need to mangle with the shell's PATH
+    if '/' not in command[0]:
+        bin_path = join(bundle.get_path(), 'bin')
+        absolute_path = join(bin_path, command[0])
+        if exists(absolute_path):
+            command[0] = absolute_path
+
+    return [mkarg(v)[1:] for v in command]
+
+def get_environ(md, bundle):
+    ret = {}
+    bin_path = join(bundle.get_path(), 'bin')
+    activity_root = env.get_profile_path(str(md['activity']))
+
+    ret['SUGAR_BUNDLE_PATH'] = bundle.get_path()
+    ret['SUGAR_BUNDLE_ID'] = str(md['activity'])
+    ret['SUGAR_ACTIVITY_ROOT'] = activity_root
+    ret['PATH'] = bin_path
+
+    if bundle.get_path().startswith(env.get_user_activities_path()):
+        ret['SUGAR_LOCALEDIR'] = join(bundle.get_path(), 'locale')
+
+    return ret
+
+def export(e):
+    md = e.metadata.get_dictionary()
+    md['object_id'] = e.object_id
+    print md['activity_id']
+
+    title = str(md.get('title', ''))
+    if 'activity_id' in md and md['activity_id'] != "":
+        title = title + "_" + str(md.get('activity_id', '')[0:8])
+    title = quote_plus(title)
+    print title
+
+    preview = md['preview']
+    del md['preview']
+
+    final_dir = title
+    dir = final_dir + ".tmp"
+
+    if exists(final_dir):
+        print 'already exists'
+        return
+
+    xos_dir = join(dir, ".xos")
+
+    mkdir_p(xos_dir)
+
+    with open(join(xos_dir, "metadata.json"), "w") as f:
+        f.write(cjson.encode(md))
+
+    with open(join(xos_dir, "preview.png"), "w") as f:
+        f.write(preview)
+
+    if e.file_path != "":
+        base, ext = splitext(title)
+        if ext == '':
+            mime_type = md['mime_type']
+            ext = sugar.mime.get_primary_extension(mime_type)
+            if ext == None: ext = ".bin"
+            else: ext = "." + ext
+        link(e.file_path, join(dir, base + ext))
+
+    if 'activity' in md and md['activity'] != '' and \
+        'activity_id' in md and md['activity_id'] != '':
+        bundle = get_bundle(md)
+        cmd = get_command(md, bundle)
+        env = get_environ(md, bundle)
+        resume_path = join(xos_dir, "resume")
+        with open(resume_path, "w") as f:
+            f.write("#!/bin/bash\n")
+            f.write("cd" + mkarg(str(bundle.get_path())) + "\n")
+            f.write("env ")
+            for k, v in env.iteritems():
+                if k == 'PATH':
+                    f.write('%s=%s' % (mkarg(k)[1:], mkarg(v)[1:]))
+                    f.write(':"$PATH"\\\n    ')
+                else:
+                    f.write('%s=%s\\\n    ' % (mkarg(k)[1:], mkarg(v)[1:]))
+            f.write(" ".join(cmd) + "\n")
+            chmod(resume_path, 0755)
+
+    rename(dir, final_dir)
+
+def main():
+    results, count = ds.find({})
+
+    for e in results:
+        try: export(e)
+        except: cgitb.handler()
+        print
+
+main()
-- 
1.7.1


More information about the Sugar-devel mailing list