From 0ec39443f711277ad044cff837b79d6b3f737400 Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Fri, 29 Nov 2013 11:45:02 +0000 Subject: fixed problems with export to Sugar app; pep8 cleanup --- diff --git a/pippy_app.py b/pippy_app.py index 6b45d55..0ca321c 100644 --- a/pippy_app.py +++ b/pippy_app.py @@ -23,6 +23,8 @@ import logging import re import os import time +import subprocess +from random import uniform from gi.repository import Gtk from gi.repository import Gdk @@ -42,6 +44,8 @@ from sugar3.activity.activity import get_bundle_path from sugar3.activity.activity import get_bundle_name from sugar3.graphics import style +from jarabe.view.customizebundle import generate_unique_id + from activity import ViewSourceActivity from activity import TARGET_TYPE_TEXT @@ -128,8 +132,8 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): gobutton.props.accelerator = _('r') gobutton.set_icon_widget(goicon_bw) gobutton.set_tooltip(_("Run!")) - gobutton.connect('clicked', self.flash_cb, dict({'bw': goicon_bw, - 'color': goicon_color})) + gobutton.connect('clicked', self.flash_cb, + dict({'bw': goicon_bw, 'color': goicon_color})) gobutton.connect('clicked', self.gobutton_cb) actions_toolbar.insert(gobutton, -1) @@ -141,8 +145,9 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): stopbutton = ToolButton(label=_("Stop")) stopbutton.props.accelerator = _('s') stopbutton.set_icon_widget(stopicon_bw) - stopbutton.connect('clicked', self.flash_cb, dict({'bw': stopicon_bw, - 'color': stopicon_color})) + stopbutton.connect('clicked', self.flash_cb, + dict({'bw': stopicon_bw, + 'color': stopicon_color})) stopbutton.connect('clicked', self.stopbutton_cb) stopbutton.set_tooltip(_("Stop")) actions_toolbar.insert(stopbutton, -1) @@ -157,8 +162,9 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): clearbutton.props.accelerator = _('c') clearbutton.set_icon_widget(clearicon_bw) clearbutton.connect('clicked', self.clearbutton_cb) - clearbutton.connect('clicked', self.flash_cb, dict({'bw': clearicon_bw, - 'color': clearicon_color})) + clearbutton.connect('clicked', self.flash_cb, + dict({'bw': clearicon_bw, + 'color': clearicon_color})) clearbutton.set_tooltip(_("Clear")) actions_toolbar.insert(clearbutton, -1) @@ -204,8 +210,6 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): olditer = self.model.insert_before(None, None) self.model.set_value(olditer, 0, direntry) self.model.set_value(olditer, 1, direntry["name"]) - - for _file in sorted(os.listdir(os.path.join(root, d))): if _file.endswith('~'): continue # skip emacs backups @@ -214,10 +218,11 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): _iter = self.model.insert_before(olditer, None) self.model.set_value(_iter, 0, entry) self.model.set_value(_iter, 1, entry["name"]) + # Adding local examples - root = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data') - direntry_examples = { "name": _("My examples"), - "path": root + "/" } + root = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'data') + direntry_examples = {"name": _("My examples"), + "path": root + "/"} self.example_iter = self.model.insert_before(None, None) self.model.set_value(self.example_iter, 0, direntry_examples) self.model.set_value(self.example_iter, 1, direntry_examples["name"]) @@ -262,8 +267,9 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): self.text_view.set_insert_spaces_instead_of_tabs(True) self.text_view.set_tab_width(2) self.text_view.set_auto_indent(True) - self.text_view.modify_font(Pango.FontDescription("Monospace " + - str(font_zoom(style.FONT_SIZE)))) + self.text_view.modify_font( + Pango.FontDescription("Monospace " + + str(font_zoom(style.FONT_SIZE)))) # We could change the color theme here, if we want to. #mgr = GtkSource.style_manager_get_default() @@ -272,7 +278,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): codesw = Gtk.ScrolledWindow() codesw.set_policy(Gtk.PolicyType.AUTOMATIC, - Gtk.PolicyType.AUTOMATIC) + Gtk.PolicyType.AUTOMATIC) codesw.add(self.text_view) self.vpane.add1(codesw) @@ -291,7 +297,8 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): self._vte.connect('child_exited', self.child_exited_cb) self._child_exited_handler = None - # FIXME It does not work because it expects and receives StructMeta Gtk.TargetEntry + # FIXME It does not work because it expects and receives StructMeta + # Gtk.TargetEntry # # self._vte.drag_dest_set(Gtk.DestDefaults.ALL, # [("text/plain", 0, TARGET_TYPE_TEXT)], @@ -406,20 +413,21 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): '%s/tmp/activity.py' % self.get_activity_root()) self._pid = self._vte.fork_command_full( - Vte.PtyFlags.DEFAULT, - get_bundle_path(), - ["/bin/sh", "-c", "python %s; sleep 1" % pippy_app_name, - "PYTHONPATH=%s/library:%s" % (get_bundle_path(), - os.getenv("PYTHONPATH", ""))], - ["PYTHONPATH=%s/library:%s" % (get_bundle_path(), - os.getenv("PYTHONPATH", ""))], - GLib.SpawnFlags.DO_NOT_REAP_CHILD, - None, - None,) + Vte.PtyFlags.DEFAULT, + get_bundle_path(), + ["/bin/sh", "-c", "python %s; sleep 1" % pippy_app_name, + "PYTHONPATH=%s/library:%s" % (get_bundle_path(), + os.getenv("PYTHONPATH", ""))], + ["PYTHONPATH=%s/library:%s" % (get_bundle_path(), + os.getenv("PYTHONPATH", ""))], + GLib.SpawnFlags.DO_NOT_REAP_CHILD, + None, + None,) def stopbutton_cb(self, button): try: - if self._pid != None: os.kill(self._pid[1], SIGTERM) + if self._pid is not None: + os.kill(self._pid[1], SIGTERM) except: pass # process must already be dead. @@ -429,8 +437,10 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): def _create_bundle_cb(self, __): from shutil import copytree, copy2, rmtree from tempfile import mkdtemp + # get the name of this pippy program. - title = self.metadata['title'] + title = self.metadata['title'].replace('.py', '') + title = title.replace('-', '') if title == 'Pippy Activity': from sugar3.graphics.alert import Alert from sugar3.graphics.icon import Icon @@ -443,6 +453,7 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): alert.connect('response', self.dismiss_alert_cb) self.add_alert(alert) return + self.stopbutton_cb(None) # try stopping old code first. self._reset_vte() self._vte.feed(_("Creating activity bundle...")) @@ -452,54 +463,54 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): os.path.join(self.get_activity_root(), TMPDIR)) sourcefile = os.path.join(app_temp, 'xyzzy.py') # invoke ourself to build the activity bundle. + self._logger.debug('writing out source file: %s' % sourcefile) + + # write out application code + self._write_text_buffer(sourcefile) + try: - # write out application code - self._write_text_buffer(sourcefile) - # hook up a callback for when the bundle builder is done. - # we can't use GObject.child_watch_add because vte will reap our - # children before we can. - self._child_exited_handler = \ - lambda: self.bundle_cb(title, app_temp) - # invoke bundle builder - self._pid = self._vte.fork_command_full( - Vte.PtyFlags.DEFAULT, - app_temp, - "/usr/bin/python", - ["/usr/bin/python", "%s/pippy_app.py" % get_bundle_path(), - '-p', '%s/library' % get_bundle_path(), - '-d', app_temp, title, sourcefile], - GLib.SpawnFlags.DO_NOT_REAP_CHILD, - None, - None) - except: + # FIXME: vte invocation was raising errors. Switched to subprocess + output = subprocess.check_output( + ["/usr/bin/python", + "%s/pippy_app.py" % get_bundle_path(), + '-p', '%s/library' % get_bundle_path(), + '-d', app_temp, title, sourcefile]) + self._vte.feed(output) + self._vte.feed("\r\n") + self.bundle_cb(title, app_temp) + except subprocess.CalledProcessError: rmtree(app_temp, ignore_errors=True) # clean up! + self._vte.feed(_('Save as Activity Error')) + self._vte.feed("\r\n") raise def _export_example_cb(self, __): # get the name of this pippy program. title = self.metadata['title'] if title == _('Pippy Activity'): - from sugar3.graphics.alert import Alert - from sugar3.graphics.icon import Icon - alert = Alert() - alert.props.title =_ ('Save as Example Error') - alert.props.msg = _('Please give your activity a meaningful name before attempting to save it as an example.') - ok_icon = Icon(icon_name='dialog-ok') - alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon) - alert.connect('response', self.dismiss_alert_cb) - self.add_alert(alert) - return - self.stopbutton_cb(None) # try stopping old code first. + from sugar3.graphics.alert import Alert + from sugar3.graphics.icon import Icon + alert = Alert() + alert.props.title = _('Save as Example Error') + alert.props.msg = _('Please give your activity a meaningful \ +name before attempting to save it as an example.') + ok_icon = Icon(icon_name='dialog-ok') + alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon) + alert.connect('response', self.dismiss_alert_cb) + self.add_alert(alert) + return + self.stopbutton_cb(None) # try stopping old code first. self._reset_vte() self._vte.feed(_("Creating example...")) self._vte.feed("\r\n") - local_data = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data') - local_file = os.path.join(local_data,title) + local_data = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'data') + local_file = os.path.join(local_data, title) if os.path.exists(local_file): from sugar3.graphics.alert import ConfirmationAlert alert = ConfirmationAlert() - alert.props.title =_ ('Save as Example Warning') - alert.props.msg = _('This example already exists. Do you want to overwrite it?') + alert.props.title = _('Save as Example Warning') + alert.props.msg = _('This example already exists. \ +Do you want to overwrite it?') alert.connect('response', self.confirmation_alert_cb, local_file) self.add_alert(alert) else: @@ -508,7 +519,6 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): self._vte.feed(_("Saved as example.")) self._vte.feed("\r\n") self.add_to_example_list(local_file) - def child_exited_cb(self, *args): """Called whenever a child exits. If there's a handler, run it.""" @@ -523,11 +533,14 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): from sugar3.datastore import datastore try: # find the .xo file: were we successful? - bundle_file = [f for f in os.listdir(app_temp) \ + bundle_file = [f for f in os.listdir(app_temp) if f.endswith('.xo')] if len(bundle_file) != 1: self._logger.debug("Couldn't find bundle: %s" % str(bundle_file)) + self._vte.feed("\r\n") + self._vte.feed(_("Error saving activity to journal.")) + self._vte.feed("\r\n") return # something went wrong. # hand off to journal os.chmod(app_temp, 0755) @@ -541,7 +554,8 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): 'mime_type': 'application/vnd.olpc-sugar', } for k, v in metadata.items(): - jobject.metadata[k] = v # the dict.update method is missing =( + # the dict.update method is missing =( + jobject.metadata[k] = v jobject.file_path = os.path.join(app_temp, bundle_file[0]) datastore.write(jobject) self._vte.feed("\r\n") @@ -555,24 +569,23 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): def dismiss_alert_cb(self, alert, response_id): self.remove_alert(alert) - - def confirmation_alert_cb(self, alert, response_id, local_file): #callback for conf alert + def confirmation_alert_cb(self, alert, response_id, local_file): + # callback for conf alert self.remove_alert(alert) if response_id is Gtk.ResponseType.OK: - self.write_file(local_file) - self._reset_vte() - self._vte.feed(_("Saved as example.")) - self._vte.feed("\r\n") + self.write_file(local_file) + self._reset_vte() + self._vte.feed(_("Saved as example.")) + self._vte.feed("\r\n") else: - self._reset_vte() + self._reset_vte() - def add_to_example_list(self,local_file): # def for add example - entry = { "name": _(os.path.basename(local_file)), - "path": local_file } + def add_to_example_list(self, local_file): # def for add example + entry = {"name": _(os.path.basename(local_file)), + "path": local_file} _iter = self.model.insert_before(self.example_iter, None) self.model.set_value(_iter, 0, entry) self.model.set_value(_iter, 1, entry["name"]) - def save_to_journal(self, file_path, cloudstring): _file = open(file_path, 'w') @@ -602,8 +615,7 @@ ACTIVITY_INFO_TEMPLATE = """ [Activity] name = %(title)s bundle_id = %(bundle_id)s -service_name = %(bundle_id)s -class = %(class)s +exec = sugar-activity %(class)s icon = activity-icon activity_version = %(version)d mime_types = %(mime_types)s @@ -612,37 +624,68 @@ show_launcher = yes """ PIPPY_ICON = \ -""" -]> +]> + - + + """ PIPPY_DEFAULT_ICON = \ """ - ]> - - + + fill="&fill_color;" stroke="&stroke_color;" stroke-width="2" d="M + 30.689595,16.460324 L 24.320145,12.001708 L 2.7550028,23.830689 L + 23.319231,38.662412 L 45.157349,26.742438 L 36.877062,21.100925" + id="path3195" /> @@ -652,7 +695,8 @@ PIPPY_DEFAULT_ICON = \ cy="6.073" r="1.927" id="circle2213" - transform="matrix(0.269108,-0.4665976,-0.472839,-0.2655557,26.503175,35.608682)" + transform="matrix(0.269108,-0.4665976,-0.472839,-0.2655557,26.503175, + 35.608682)" /> """ @@ -660,10 +704,12 @@ PIPPY_DEFAULT_ICON = \ ############# ACTIVITY META-INFORMATION ############### # this is used by Pippy to generate a bundle for itself. + def pippy_activity_version(): """Returns the version number of the generated activity bundle.""" return 39 + def pippy_activity_extra_files(): """Returns a map of 'extra' files which should be included in the generated activity bundle.""" @@ -678,27 +724,33 @@ def pippy_activity_extra_files(): extra['activity/activity-default.svg'] = PIPPY_DEFAULT_ICON return extra + def pippy_activity_news(): """Return the NEWS file for this activity.""" # Cheat again. return open(os.path.join(get_bundle_path(), 'NEWS')).read() + def pippy_activity_icon(): """Return an SVG document specifying the icon for this activity.""" return PIPPY_ICON + def pippy_activity_class(): """Return the class which should be started to run this activity.""" return 'pippy_app.PippyActivity' + def pippy_activity_bundle_id(): """Return the bundle_id for the generated activity.""" return 'org.laptop.Pippy' + def pippy_activity_mime_types(): """Return the mime types handled by the generated activity, as a list.""" return ['text/x-python', groupthink_mimetype] + def pippy_activity_extra_info(): return """ license = GPLv2+ @@ -706,6 +758,7 @@ update_url = http://activities.sugarlabs.org """ ################# ACTIVITY BUNDLER ################ + def main(): """Create a bundle from a pippy-style source file""" from optparse import OptionParser @@ -715,6 +768,7 @@ def main(): from sugar3 import profile from sugar3.activity import bundlebuilder import sys + parser = OptionParser(usage='%prog [options] [title] [sourcefile]') parser.add_option('-d', '--dir', dest='dir', default='.', metavar='DIR', help='Put generated bundle in the specified directory.') @@ -724,11 +778,13 @@ def main(): (options, args) = parser.parse_args() if len(args) != 2: parser.error('The title and sourcefile arguments are required.') + title = args[0] sourcefile = args[1] pytitle = re.sub(r'[^A-Za-z0-9_]', '', title) if re.match(r'[0-9]', pytitle) is not None: pytitle = '_' + pytitle # first character cannot be numeric + # first take a gander at the source file and see if it's got extra info # for us. sourcedir, basename = os.path.split(sourcefile) @@ -742,12 +798,15 @@ def main(): 'news': 'No news.', 'icon': PIPPY_DEFAULT_ICON, 'class': 'activity.VteActivity', - 'bundle_id': ('org.laptop.pippy.%s' % pytitle), + 'bundle_id': ('org.sugarlabs.pippy.%s%d' % + (generate_unique_id(), + int(round(uniform(1000, 9999), 0)))), 'mime_types': '', 'extra_info': '', } # are any of these things in the module? try_import = False + info = readmodule_ex(module, [sourcedir] + options.path) for func in bundle_info.keys(): p_a_func = 'pippy_activity_%s' % func @@ -792,28 +851,25 @@ def main(): f.write(contents) # put script into $app_temp/pippy_app.py copy2(sourcefile, '%s/pippy_app.py' % app_temp) - # write MANIFEST file. - with open('%s/MANIFEST' % app_temp, 'w') as f: - for dirpath, dirnames, filenames in sorted(os.walk(app_temp)): - for name in sorted(filenames): - fn = os.path.join(dirpath, name) - fn = fn.replace(app_temp + '/', '') - if fn == 'MANIFEST': - continue - f.write('%s\n' % fn) # invoke bundle builder olddir = os.getcwd() oldargv = sys.argv os.chdir(app_temp) sys.argv = ['setup.py', 'dist_xo'] + print('\r\nStarting bundlebuilder\r\n') bundlebuilder.start() sys.argv = oldargv os.chdir(olddir) # move to destination directory. - copy2('%s/dist/%s-%d.xo' % (app_temp, pytitle, bundle_info['version']), - '%s/%s-%d.xo' % (options.dir, pytitle, bundle_info['version'])) + src = '%s/dist/%s-%d.xo' % (app_temp, pytitle, bundle_info['version']) + dst = '%s/%s-%d.xo' % (options.dir, pytitle, bundle_info['version']) + if not os.path.exists(src): + print('Cannot find %s\r\n' % (src)) + else: + copy2(src, dst) finally: rmtree(app_temp, ignore_errors=True) + print('Finally\r\n') if __name__ == '__main__': from gettext import gettext as _ @@ -821,8 +877,8 @@ if __name__ == '__main__': if False: # change this to True to test within Pippy sys.argv = sys.argv + ['-d', '/tmp', 'Pippy', '/home/olpc/pippy_app.py'] - #print _("Working..."), - #sys.stdout.flush() + print(_("Working...")) + sys.stdout.flush() main() - #print _("done!") + print(_("done!")) sys.exit(0) -- cgit v0.9.1