From 881e840aa6fc7380fa3fb65de350538c1a88518d Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Sun, 12 Jan 2014 18:00:04 +0000 Subject: adding new authors to copyright --- diff --git a/pippy_app.py b/pippy_app.py index b187e87..5996dd2 100644 --- a/pippy_app.py +++ b/pippy_app.py @@ -25,157 +25,108 @@ """Pippy Activity: A simple Python programming activity .""" from __future__ import with_statement +import gtk import logging +import pango +import vte import re import os -import subprocess -from random import uniform -import locale -import json -import sys - -import dbus -from dbus.mainloop.glib import DBusGMainLoop - -DBusGMainLoop(set_as_default=True) -bus = dbus.SessionBus() - -from gi.repository import Gtk -from gi.repository import Gdk -from gi.repository import GLib -from gi.repository import Pango -from gi.repository import Vte -from gi.repository import GObject +import gobject +import time from port.style import font_zoom from signal import SIGTERM from gettext import gettext as _ -from sugar3.datastore import datastore -from sugar3.activity.widgets import EditToolbar -from sugar3.activity.widgets import StopButton -from sugar3.activity.activity import get_bundle_name -<<<<<<< HEAD -from sugar3.activity.activity import get_bundle_path -from sugar3.graphics.alert import Alert -from sugar3.graphics.alert import ConfirmationAlert -======= ->>>>>>> 3ee39682ad9bc3daf6c67b95b9c8acb42b995d4d -from sugar3.graphics.alert import NotifyAlert -from sugar3.graphics import style -from sugar3.graphics.icon import Icon -from sugar3.graphics.objectchooser import ObjectChooser -from sugar3.graphics.toggletoolbutton import ToggleToolButton - -from jarabe.view.customizebundle import generate_unique_id - +from sugar.activity import activity from activity import ViewSourceActivity from activity import TARGET_TYPE_TEXT +from sugar.activity.activity import ActivityToolbox +from sugar.activity.activity import EditToolbar +from sugar.activity.activity import get_bundle_path +from sugar.activity.activity import get_bundle_name +from sugar.graphics import style +from sugar.graphics.toolbutton import ToolButton import groupthink.sugar_tools import groupthink.gtk_tools -from filedialog import FileDialog -from icondialog import IconDialog - text_buffer = None # magic prefix to use utf-8 source encoding -PYTHON_PREFIX = '''#!/usr/bin/python +PYTHON_PREFIX = """#!/usr/bin/python # -*- coding: utf-8 -*- -''' -# Force category names into Pootle -DEFAULT_CATEGORIES = [_('graphics'), _('math'), _('pyhton'), _('sound'), - _('string'), _('tutorials')] +""" -from sugar3.graphics.toolbarbox import ToolbarButton -from sugar3.graphics.toolbutton import ToolButton +OLD_TOOLBAR = False +try: + from sugar.graphics.toolbarbox import ToolbarBox + from sugar.graphics.toolbarbox import ToolbarButton + from sugar.activity.widgets import StopButton +except ImportError: + OLD_TOOLBAR = True # get screen sizes -SIZE_X = Gdk.Screen.width() -SIZE_Y = Gdk.Screen.height() +SIZE_X = gtk.gdk.screen_width() +SIZE_Y = gtk.gdk.screen_height() groupthink_mimetype = 'pickle/groupthink-pippy' -from notebook import SourceNotebook - -DISUTILS_SETUP_SCRIPT = """#!/usr/bin/python -# -*- coding: utf-8 -*- -from distutils.core import setup -setup(name='{modulename}', - version='1.0', - py_modules=[ - {filenames} - ], - ) -""" # This is .format()'ed with the list of the file names. - class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): - '''Pippy Activity as specified in activity.info''' + """Pippy Activity as specified in activity.info""" def early_setup(self): - from gi.repository import GtkSource - self.initial_text_buffer = GtkSource.Buffer() - self.loaded_from_journal = False - self.py_file = False - self.loaded_session = [] - self.session_data = [] - - sys.path.append(os.path.join(self.get_activity_root(), 'Library')) + global text_buffer + import gtksourceview2 + text_buffer = gtksourceview2.Buffer() def initialize_display(self): self._logger = logging.getLogger('pippy-activity') # Activity toolbar with title input, share button and export buttons: - activity_toolbar = self.activity_button.page + if OLD_TOOLBAR: + activity_toolbar = self.toolbox.get_activity_toolbar() + else: + activity_toolbar = self.activity_button.page + + # Hide keep button for Sugar versions prior to 0.94: + activity_toolbar.keep.hide() - separator = Gtk.SeparatorToolItem() + separator = gtk.SeparatorToolItem() separator.show() activity_toolbar.insert(separator, -1) - import_py_button = ToolButton('pippy-import-doc') - import_py_button.set_tooltip(_('Import Python file to new tab')) - import_py_button.connect('clicked', self._import_py_cb) - import_py_button.show() - activity_toolbar.insert(import_py_button, -1) - - export_doc_button = ToolButton('pippy-export-doc') - export_doc_button.set_tooltip(_('Export as Pippy document')) + export_doc_button = ToolButton('pippy-export_doc') + export_doc_button.set_tooltip(_("Export as Pippy Document")) export_doc_button.connect('clicked', self._export_document_cb) export_doc_button.show() activity_toolbar.insert(export_doc_button, -1) - save_as_library = ToolButton('pippy-export-library') - save_as_library.set_tooltip(_('Save this file to the Pippy library')) - save_as_library.connect('clicked', self._save_as_library) - save_as_library.show() - activity_toolbar.insert(save_as_library, -1) - - export_example_button = ToolButton('pippy-export-example') - export_example_button.set_tooltip(_('Export as new Pippy example')) + export_example_button = ToolButton('pippy-export_example') + export_example_button.set_tooltip(_("Export as Pippy Example")) export_example_button.connect('clicked', self._export_example_cb) export_example_button.show() activity_toolbar.insert(export_example_button, -1) - create_bundle_button = ToolButton('pippy-create-bundle') - create_bundle_button.set_tooltip(_('Create a Sugar activity bundle')) + create_bundle_button = ToolButton('pippy-create_bundle') + create_bundle_button.set_tooltip(_("Create Activity Bundle")) create_bundle_button.connect('clicked', self._create_bundle_cb) create_bundle_button.show() activity_toolbar.insert(create_bundle_button, -1) - export_disutils = ToolButton('pippy-create-disutils') - export_disutils.set_tooltip(_('Export as a disutils package')) - export_disutils.connect('clicked', self.__export_disutils_cb) - export_disutils.show() - activity_toolbar.insert(export_disutils, -1) - - self._edit_toolbar = EditToolbar() + self._edit_toolbar = activity.EditToolbar() - edit_toolbar_button = ToolbarButton() - edit_toolbar_button.set_page(self._edit_toolbar) - edit_toolbar_button.props.icon_name = 'toolbar-edit' - edit_toolbar_button.props.label = _('Edit') - self.get_toolbar_box().toolbar.insert(edit_toolbar_button, -1) + if OLD_TOOLBAR: + activity_toolbar = gtk.Toolbar() + self.toolbox.add_toolbar(_('Actions'), activity_toolbar) + self.toolbox.set_current_toolbar(1) + self.toolbox.add_toolbar(_('Edit'), self._edit_toolbar) + else: + edit_toolbar_button = ToolbarButton() + edit_toolbar_button.set_page(self._edit_toolbar) + edit_toolbar_button.props.icon_name = 'toolbar-edit' + edit_toolbar_button.props.label = _('Edit') + self.get_toolbar_box().toolbar.insert(edit_toolbar_button, -1) self._edit_toolbar.show() @@ -184,190 +135,196 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): self._edit_toolbar.copy.connect('clicked', self.__copybutton_cb) self._edit_toolbar.paste.connect('clicked', self.__pastebutton_cb) - actions_toolbar = self.get_toolbar_box().toolbar - - self.toggle_output = ToggleToolButton('tray-show') - self.toggle_output.set_tooltip(_('Show output panel')) - self.toggle_output.connect('toggled', self._toggle_output_cb) - actions_toolbar.insert(self.toggle_output, -1) + if OLD_TOOLBAR: + actions_toolbar = activity_toolbar + else: + actions_toolbar = self.get_toolbar_box().toolbar # The "go" button - goicon_bw = Gtk.Image() - goicon_bw.set_from_file('%s/icons/run_bw.svg' % os.getcwd()) - goicon_color = Gtk.Image() - goicon_color.set_from_file('%s/icons/run_color.svg' % os.getcwd()) - gobutton = ToolButton(label=_('Run!')) + goicon_bw = gtk.Image() + goicon_bw.set_from_file("%s/icons/run_bw.svg" % os.getcwd()) + goicon_color = gtk.Image() + goicon_color.set_from_file("%s/icons/run_color.svg" % os.getcwd()) + gobutton = ToolButton(label=_("Run!")) 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.set_tooltip(_("Run!")) + gobutton.connect('clicked', self.flash_cb, dict({'bw': goicon_bw, + 'color': goicon_color})) gobutton.connect('clicked', self.gobutton_cb) actions_toolbar.insert(gobutton, -1) # The "stop" button - stopicon_bw = Gtk.Image() - stopicon_bw.set_from_file('%s/icons/stopit_bw.svg' % os.getcwd()) - stopicon_color = Gtk.Image() - stopicon_color.set_from_file('%s/icons/stopit_color.svg' % os.getcwd()) - stopbutton = ToolButton(label=_('Stop')) + stopicon_bw = gtk.Image() + stopicon_bw.set_from_file("%s/icons/stopit_bw.svg" % os.getcwd()) + stopicon_color = gtk.Image() + stopicon_color.set_from_file("%s/icons/stopit_color.svg" % os.getcwd()) + 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')) + stopbutton.set_tooltip(_("Stop")) actions_toolbar.insert(stopbutton, -1) # The "clear" button - clearicon_bw = Gtk.Image() - clearicon_bw.set_from_file('%s/icons/eraser_bw.svg' % os.getcwd()) - clearicon_color = Gtk.Image() - clearicon_color.set_from_file('%s/icons/eraser_color.svg' % + clearicon_bw = gtk.Image() + clearicon_bw.set_from_file("%s/icons/eraser_bw.svg" % os.getcwd()) + clearicon_color = gtk.Image() + clearicon_color.set_from_file("%s/icons/eraser_color.svg" % os.getcwd()) - clearbutton = ToolButton(label=_('Clear')) + clearbutton = ToolButton(label=_("Clear")) 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.set_tooltip(_('Clear')) + clearbutton.connect('clicked', self.flash_cb, dict({'bw': clearicon_bw, + 'color': clearicon_color})) + clearbutton.set_tooltip(_("Clear")) actions_toolbar.insert(clearbutton, -1) activity_toolbar.show() - examples = ToolButton('pippy-openoff') - examples.set_tooltip(_('Load example')) - examples.connect('clicked', self.load_example) - - self.get_toolbar_box().toolbar.insert(Gtk.SeparatorToolItem(), -1) - self.get_toolbar_box().toolbar.insert(examples, -1) - - separator = Gtk.SeparatorToolItem() - separator.props.draw = False - separator.set_expand(True) - self.get_toolbar_box().toolbar.insert(separator, -1) - separator.show() - - stop = StopButton(self) - self.get_toolbar_box().toolbar.insert(stop, -1) - - self.paths = [] - - vpane = Gtk.Paned.new(orientation=Gtk.Orientation.VERTICAL) - vpane.set_position(400) # setting initial position - - self.paths = [] - - data_path = os.path.join(get_bundle_path(), 'data') - - # get default language from locale - locale_lang = locale.getdefaultlocale()[0] - if locale_lang is None: - lang = 'en' + if not OLD_TOOLBAR: + separator = gtk.SeparatorToolItem() + separator.props.draw = False + separator.set_expand(True) + self.get_toolbar_box().toolbar.insert(separator, -1) + separator.show() + + stop = StopButton(self) + self.get_toolbar_box().toolbar.insert(stop, -1) + + # Main layout. + self.hpane = gtk.HPaned() + self.vpane = gtk.VPaned() + + # The sidebar. + self.sidebar = gtk.VBox() + self.model = gtk.TreeStore(gobject.TYPE_PYOBJECT, gobject.TYPE_STRING) + treeview = gtk.TreeView(self.model) + cellrenderer = gtk.CellRendererText() + treecolumn = gtk.TreeViewColumn(_("Examples"), cellrenderer, text=1) + treeview.get_selection().connect("changed", self.selection_cb) + treeview.append_column(treecolumn) + treeview.set_size_request(int(SIZE_X * 0.3), SIZE_Y) + + # Create scrollbars around the view. + scrolled = gtk.ScrolledWindow() + scrolled.add(treeview) + self.sidebar.pack_start(scrolled) + self.hpane.add1(self.sidebar) + + root = os.path.join(get_bundle_path(), 'data') + for d in sorted(os.listdir(root)): + if not os.path.isdir(os.path.join(root, d)): + continue # skip non-dirs + direntry = {"name": _(d.capitalize()), + "path": os.path.join(root, d) + "/"} + 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 + entry = {"name": _(_file.capitalize()), + "path": os.path.join(root, d, _file)} + _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 + "/" } + 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"]) + for _file in sorted(os.listdir(root)): + file_name = os.path.join(root, _file) + if os.path.isfile(file_name): + entry = {"name": _file, "path": file_name} + _iter = self.model.insert_before(self.example_iter, None) + self.model.set_value(_iter, 0, entry) + self.model.set_value(_iter, 1, entry["name"]) + + treeview.expand_all() + + # Source buffer + import gtksourceview2 + global text_buffer + lang_manager = gtksourceview2.language_manager_get_default() + if hasattr(lang_manager, 'list_languages'): + langs = lang_manager.list_languages() else: - lang = locale_lang.split('_')[0] - logging.debug(locale.getdefaultlocale()) - logging.debug(lang) - - # construct the path for both - lang_path = os.path.join(data_path, lang) - en_lang_path = os.path.join(data_path, 'en') - - # get all folders in lang examples - self.all_folders = [] - if os.path.exists(lang_path): - for d in sorted(os.listdir(lang_path)): - self.all_folders.append(d) - - # get all folders in English examples - for d in sorted(os.listdir(en_lang_path)): - # check if folder isn't already in list - if d not in self.all_folders: - self.all_folders.append(d) - - for folder in self.all_folders: - direntry = {} - # check if dir exists in pref language, if exists, add it - if os.path.exists(os.path.join(lang_path, folder)): - direntry = { - 'name': _(folder.capitalize()), - 'path': os.path.join(lang_path, folder) + '/'} - # if not try to see if it's in default English path - elif os.path.exists(os.path.join(en_lang_path, folder)): - direntry = { - 'name': _(folder.capitalize()), - 'path': os.path.join(en_lang_path, folder) + '/'} - self.paths.append([direntry['name'], direntry['path']]) - - # Adding local examples - root = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], 'data') - self.paths.append([_('My examples'), root]) - - self.source_tabs = SourceNotebook(self) - self.source_tabs.connect('tab-added', self._add_source_cb) - if self.loaded_from_journal and self.py_file: - self.source_tabs.add_tab( - self.initial_title, - self.initial_text_buffer) - elif self.loaded_session: - for name, content in self.loaded_session: - self.source_tabs.add_tab(name, content) + lang_ids = lang_manager.get_language_ids() + langs = [lang_manager.get_language(lang_id) + for lang_id in lang_ids] + for lang in langs: + for m in lang.get_mime_types(): + if m == "text/x-python": + text_buffer.set_language(lang) + + if hasattr(text_buffer, 'set_highlight'): + text_buffer.set_highlight(True) else: - self.source_tabs.add_tab() - - vpane.add1(self.source_tabs) - - outbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL) - self._vte = Vte.Terminal() + text_buffer.set_highlight_syntax(True) + + # The GTK source view window + self.text_view = gtksourceview2.View(text_buffer) + self.text_view.set_size_request(0, int(SIZE_Y * 0.5)) + self.text_view.set_editable(True) + self.text_view.set_cursor_visible(True) + self.text_view.set_show_line_numbers(True) + self.text_view.set_wrap_mode(gtk.WRAP_CHAR) + 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)))) + + # We could change the color theme here, if we want to. + #mgr = gtksourceview2.style_manager_get_default() + #style_scheme = mgr.get_scheme('kate') + #self.text_buffer.set_style_scheme(style_scheme) + + codesw = gtk.ScrolledWindow() + codesw.set_policy(gtk.POLICY_AUTOMATIC, + gtk.POLICY_AUTOMATIC) + codesw.add(self.text_view) + self.vpane.add1(codesw) + + # An hbox to hold the vte window and its scrollbar. + outbox = gtk.HBox() + + # The vte python window + self._vte = vte.Terminal() self._vte.set_encoding('utf-8') self._vte.set_size(30, 5) font = 'Monospace ' + str(font_zoom(style.FONT_SIZE)) - self._vte.set_font(Pango.FontDescription(font)) - self._vte.set_colors(Gdk.color_parse('#000000'), - Gdk.color_parse('#E7E7E7'), + self._vte.set_font(pango.FontDescription(font)) + self._vte.set_colors(gtk.gdk.color_parse('#000000'), + gtk.gdk.color_parse('#E7E7E7'), []) self._vte.connect('child_exited', self.child_exited_cb) - self._child_exited_handler = None + self._vte.drag_dest_set(gtk.DEST_DEFAULT_ALL, + [("text/plain", 0, TARGET_TYPE_TEXT)], + gtk.gdk.ACTION_COPY) self._vte.connect('drag_data_received', self.vte_drop_cb) - outbox.pack_start(self._vte, True, True, 0) + outbox.pack_start(self._vte) - outsb = Gtk.Scrollbar(orientation=Gtk.Orientation.VERTICAL) - outsb.set_adjustment(self._vte.get_vadjustment()) + outsb = gtk.VScrollbar(self._vte.get_adjustment()) outsb.show() outbox.pack_start(outsb, False, False, 0) - vpane.add2(outbox) - self.outbox = outbox - - return vpane - - def after_init(self): - self.outbox.hide() - - def _toggle_output_cb(self, button): - shown = button.get_active() - if shown: - self.outbox.show_all() - self.toggle_output.set_tooltip(_('Hide output panel')) - self.toggle_output.set_icon_name('tray-hide') - else: - self.outbox.hide() - self.toggle_output.set_tooltip(_('Show output panel')) - self.toggle_output.set_icon_name('tray-show') - - def load_example(self, widget): - widget.set_icon_name('pippy-openon') - dialog = FileDialog(self.paths, self, widget) - dialog.run() - path = dialog.get_path() - if path: - self._select_func_cb(path) + self.vpane.add2(outbox) + self.hpane.add2(self.vpane) + return self.hpane def when_shared(self): - text_buffer = self.source_tabs.get_text_buffer() + self.hpane.remove(self.hpane.get_child1()) + global text_buffer self.cloud.sharefield = \ groupthink.gtk_tools.TextBufferSharePoint(text_buffer) # HACK : There are issues with undo/redoing while in shared @@ -376,56 +333,24 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): self._edit_toolbar.undo.set_sensitive(False) self._edit_toolbar.redo.set_sensitive(False) - def _add_source_cb(self, button): - self.source_tabs.add_tab() - self.source_tabs.get_nth_page(-1).show_all() - def vte_drop_cb(self, widget, context, x, y, selection, targetType, time): if targetType == TARGET_TYPE_TEXT: self._vte.feed_child(selection.data) - def selection_cb(self, value): + def selection_cb(self, column): self.save() - self._logger.debug('clicked! %s' % value['path']) + model, _iter = column.get_selected() + value = model.get_value(_iter, 0) + self._logger.debug("clicked! %s" % value['path']) _file = open(value['path'], 'r') lines = _file.readlines() - text_buffer = self.source_tabs.get_text_buffer() - text_buffer.set_text(''.join(lines)) - text_buffer.set_modified(False) + global text_buffer + text_buffer.set_text("".join(lines)) self.metadata['title'] = value['name'] self.stopbutton_cb(None) self._reset_vte() self.text_view.grab_focus() - def _select_func_cb(self, path): - text_buffer = self.source_tabs.get_text_buffer() - if text_buffer.get_modified(): - alert = ConfirmationAlert() - alert.props.title = _('Example selection Warning') - alert.props.msg = \ - _('You have modified the currently selected file. ' - 'Discard changes?') - alert.connect('response', self._discard_changes_cb, path) - self.add_alert(alert) - return False - else: - values = {} - values['name'] = os.path.basename(path) - values['path'] = path - self.selection_cb(values) - - return False - - def _discard_changes_cb(self, alert, response_id, path): - self.remove_alert(alert) - if response_id is Gtk.ResponseType.OK: - values = {} - values['name'] = os.path.basename(path) - values['path'] = path - self.selection_cb(values) - text_buffer = self.source_tabs.get_text_buffer() - text_buffer.set_modified(False) - def timer_cb(self, button, icons): button.set_icon_widget(icons['bw']) button.show_all() @@ -434,367 +359,187 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): def flash_cb(self, button, icons): button.set_icon_widget(icons['color']) button.show_all() - GObject.timeout_add(400, self.timer_cb, button, icons) + gobject.timeout_add(400, self.timer_cb, button, icons) def clearbutton_cb(self, button): self.save() - text_buffer = self.source_tabs.get_text_buffer() - text_buffer.set_text('') - text_buffer.set_modified(False) + global text_buffer + text_buffer.set_text("") self.metadata['title'] = _('%s Activity') % get_bundle_name() self.stopbutton_cb(None) self._reset_vte() - self.source_tabs.get_text_view().grab_focus() - - def _write_all_buffers(self, tmp_dir): - data = self.source_tabs.get_all_data() - zipdata = zip(data[0], data[1]) - for name, content in zipdata: - with open(os.path.join(tmp_dir, name), 'w') as f: - # Write utf-8 coding prefix if there's not one already - if re.match(r'coding[:=]\s*([-\w.]+)', - '\n'.join(content.splitlines()[:2])) is None: - f.write(PYTHON_PREFIX) - f.write(content) + self.text_view.grab_focus() + + def _write_text_buffer(self, filename): + global text_buffer + start, end = text_buffer.get_bounds() + text = text_buffer.get_text(start, end) + + with open(filename, 'w') as f: + # write utf-8 coding prefix if there's not already one + if re.match(r'coding[:=]\s*([-\w.]+)', + '\n'.join(text.splitlines()[:2])) is None: + f.write(PYTHON_PREFIX) + for line in text: + f.write(line) def _reset_vte(self): self._vte.grab_focus() - self._vte.feed('\x1B[H\x1B[J\x1B[0;39m') + self._vte.feed("\x1B[H\x1B[J\x1B[0;39m") - def __undobutton_cb(self, butston): - text_buffer = self.source_tabs.get_text_buffer() + def __undobutton_cb(self, button): + global text_buffer if text_buffer.can_undo(): text_buffer.undo() def __redobutton_cb(self, button): - text_buffer = self.source_tabs.get_text_buffer() + global text_buffer if text_buffer.can_redo(): text_buffer.redo() def __copybutton_cb(self, button): -<<<<<<< HEAD - text_buffer = self.source_tabs.get_text_buffer() - text_buffer.copy_clipboard(Gtk.Clipboard()) - - def __pastebutton_cb(self, button): - text_buffer = self.source_tabs.get_text_buffer() - text_buffer.paste_clipboard(Gtk.Clipboard(), None, True) -======= global text_buffer - clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) - text_buffer.copy_clipboard(clipboard) + text_buffer.copy_clipboard(gtk.Clipboard()) def __pastebutton_cb(self, button): global text_buffer - clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) - text_buffer.paste_clipboard(clipboard, None, True) ->>>>>>> 3ee39682ad9bc3daf6c67b95b9c8acb42b995d4d + text_buffer.paste_clipboard(gtk.Clipboard(), None, True) def gobutton_cb(self, button): from shutil import copy2 - self.stopbutton_cb(button) # Try stopping old code first. + self.stopbutton_cb(button) # try stopping old code first. self._reset_vte() # FIXME: We're losing an odd race here - # Gtk.main_iteration(block=False) - - if self.toggle_output.get_active() is False: - self.outbox.show_all() - self.toggle_output.set_active(True) - - pippy_tmp_dir = '%s/tmp/' % self.get_activity_root() - self._write_all_buffers(pippy_tmp_dir) - - current_file = os.path.join( - pippy_tmp_dir, - self.source_tabs.get_current_file_name()) + # gtk.main_iteration(block=False) - # Write activity.py here too, to support pippy-based activities. + pippy_app_name = '%s/tmp/pippy_app.py' % self.get_activity_root() + self._write_text_buffer(pippy_app_name) + # write activity.py here too, to support pippy-based activities. copy2('%s/activity.py' % get_bundle_path(), '%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' % current_file, - '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,) + self._pid = self._vte.fork_command( + command="/bin/sh", + argv=["/bin/sh", "-c", + "python %s; sleep 1" % pippy_app_name], + envv=["PYTHONPATH=%s/library:%s" % (get_bundle_path(), + os.getenv("PYTHONPATH", ""))], + directory=get_bundle_path()) def stopbutton_cb(self, button): try: - if self._pid is not None: - os.kill(self._pid[1], SIGTERM) + os.kill(self._pid, SIGTERM) except: - pass # Process must already be dead. - - def _save_as_library(self, button): - library_dir = os.path.join(get_bundle_path(), 'library') - file_name = self.source_tabs.get_current_file_name() - text_buffer = self.source_tabs.get_text_buffer() - content = text_buffer.get_text( - *text_buffer.get_bounds(), - include_hidden_chars=True) - - if not os.path.isdir(library_dir): - os.mkdir(library_dir) - - with open(os.path.join(library_dir, file_name), 'w') as f: - f.write(content) - success = True - - if success: - alert = NotifyAlert(5) - alert.props.title = _('Python File added to Library') - IMPORT_MESSAGE = _('The file you selected has been added' - ' to the library. Use "import {importname}"' - ' to import the library for using.') - alert.props.msg = IMPORT_MESSAGE.format(importname=file_name[:-3]) - alert.connect('response', self.remove_alert_cb) - self.add_alert(alert) + pass # process must already be dead. def _export_document_cb(self, __): self.copy() - alert = NotifyAlert() - alert.props.title = _('Saved') - alert.props.msg = _('The document has been saved to journal.') - alert.connect('response', lambda x, i: self.remove_alert(x)) - self.add_alert(alert) - - def remove_alert_cb(self, alert, response_id): - self.remove_alert(alert) - - def _import_py_cb(self, button): - chooser = ObjectChooser() - result = chooser.run() - if result is Gtk.ResponseType.ACCEPT: - dsitem = chooser.get_selected_object() - if dsitem.metadata['mime_type'] != 'text/x-python': - alert = NotifyAlert(5) - alert.props.title = _('Error importing Python file') - alert.props.msg = _('The file you selected is not a ' - 'Python file.') - alert.connect('response', self.remove_alert_cb) - self.add_alert(alert) - elif dsitem.object_id in self.session_data: - alert = NotifyAlert(5) - alert.props.title = _('Error importing Python file') - alert.props.msg = _('The file you selected is already ' - 'open') - alert.connect('response', self.remove_alert_cb) - self.add_alert(alert) - else: - name = dsitem.metadata['title'] - file_path = dsitem.get_file_path() - content = open(file_path, 'r').read() - - self.source_tabs.add_tab(name, content) - self.session_data.append(dsitem.object_id) - - chooser.destroy() def _create_bundle_cb(self, __): + from shutil import copytree + from shutil import copy2 from shutil import rmtree from tempfile import mkdtemp - - # Get the name of this pippy program. - title = self.metadata['title'].replace('.py', '') - title = title.replace('-', '') + # get the name of this pippy program. + title = self.metadata['title'] if title == 'Pippy Activity': + from sugar.graphics.alert import Alert + from sugar.graphics.icon import Icon alert = Alert() alert.props.title = _('Save as Activity Error') alert.props.msg = _('Please give your activity a meaningful name ' 'before attempting to save it as an activity.') ok_icon = Icon(icon_name='dialog-ok') - alert.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon) + alert.add_button(gtk.RESPONSE_OK, _('Ok'), ok_icon) alert.connect('response', self.dismiss_alert_cb) self.add_alert(alert) return - - alert_icon = Alert() - ok_icon = Icon(icon_name='dialog-ok') - alert_icon.add_button(Gtk.ResponseType.OK, _('Ok'), ok_icon) - alert_icon.props.title = _('Activity icon') - alert_icon.props.msg = _('Please select an activity icon.') - - def internal_callback(window=None, event=None): - icon = '%s/activity/activity-default.svg' % (get_bundle_path()) - if window: - icon = window.get_icon() - self.stopbutton_cb(None) # Try stopping old code first. - self._reset_vte() - self._vte.feed(_('Creating activity bundle...')) - self._vte.feed('\r\n') - - TMPDIR = 'instance' - app_temp = mkdtemp('.activity', 'Pippy', - 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.stopbutton_cb(None) # try stopping old code first. + self._reset_vte() + self._vte.feed(_("Creating activity bundle...")) + self._vte.feed("\r\n") + TMPDIR = 'instance' + app_temp = mkdtemp('.activity', 'Pippy', + os.path.join(self.get_activity_root(), TMPDIR)) + sourcefile = os.path.join(app_temp, 'xyzzy.py') + # invoke ourself to build the activity bundle. + try: + # write out application code self._write_text_buffer(sourcefile) - - try: - # FIXME: vte invocation was raising errors. - # Switched to subprocss - 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, icon]) - 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 alert_response(alert, response_id): - self.remove_alert(alert) - - def dialog(): - dialog = IconDialog() - dialog.connect('destroy', internal_callback) - - GObject.idle_add(dialog) - - alert_icon.connect('response', alert_response) - self.add_alert(alert_icon) - - def _write_text_buffer(self, filename): - text_buffer = self.source_tabs.get_text_buffer() - start, end = text_buffer.get_bounds() - text = text_buffer.get_text(start, end, True) - - with open(filename, 'w') as f: - # Write utf-8 coding prefix if there's not one already - if re.match(r'coding[:=]\s*([-\w.]+)', - '\n'.join(text.splitlines()[:2])) is None: - f.write(PYTHON_PREFIX) - for line in text: - f.write(line) - - def __export_disutils_cb(self, button): - app_temp = os.path.join(self.get_activity_root(), 'instance') - data = self.source_tabs.get_all_data() - for filename, content in zip(data[0], data[1]): - fileobj = open(os.path.join(app_temp, filename), 'w') - fileobj.write(content) - fileobj.close() - - filenames = ','.join([("'"+name[:-3]+"'") for name in data[0]]) - - title = self.metadata['title'] - if title is _('Pippy Activity'): - from sugar3.graphics.alert import Alert - from sugar3.graphics.icon import Icon - alert = Alert() - alert.props.title = _('Save as disutils package error') - alert.props.msg = _('Please give your activity a meaningful' - 'name before attempting to save it ' - 'as an disutils package.') - 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 - - setup_script = DISUTILS_SETUP_SCRIPT.format(modulename=title, - filenames=filenames) - setupfile = open(os.path.join(app_temp, 'setup.py'), 'w') - setupfile.write(setup_script) - setupfile.close() - - os.chdir(app_temp) - - subprocess.check_output( - [ - '/usr/bin/python', - os.path.join(app_temp, 'setup.py'), - 'sdist', '-v' - ]) - - # Hand off to journal - os.chmod(app_temp, 0777) - jobject = datastore.create() - metadata = { - 'title': '%s disutils bundle' % title, - 'title_set_by_user': '1', - 'mime_type': 'application/x-gzip', - } - for k, v in metadata.items(): - # The dict.update method is missing =( - jobject.metadata[k] = v - tarname = 'dist/{modulename}-1.0.tar.gz'.format(modulename=title) - jobject.file_path = os.path.join(app_temp, tarname) - datastore.write(jobject) + # 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( + command="/usr/bin/python", + argv=["/usr/bin/python", + "%s/pippy_app.py" % get_bundle_path(), + '-p', '%s/library' % get_bundle_path(), + '-d', app_temp, + title, sourcefile], + directory=app_temp) + except: + rmtree(app_temp, ignore_errors=True) # clean up! + raise def _export_example_cb(self, __): - # Get the name of this pippy program. + # 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 sugar.graphics.alert import Alert + from sugar.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.RESPONSE_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) + 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) if os.path.exists(local_file): + from sugar.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: - self.write_file(local_file) - self._reset_vte() - self._vte.feed(_('Saved as example.')) - self._vte.feed('\r\n') - self.add_to_example_list(local_file) + self.write_file(local_file) + self._reset_vte() + 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.''' + """Called whenever a child exits. If there's a handler, run it.""" h, self._child_exited_handler = self._child_exited_handler, None if h is not None: h() def bundle_cb(self, title, app_temp): - '''Called when we're done building a bundle for a source file.''' - from sugar3 import profile + """Called when we're done building a bundle for a source file.""" + from sugar import profile from shutil import rmtree + from sugar.datastore import datastore try: - # Find the .xo file: were we successful? - bundle_file = [f for f in os.listdir(app_temp) + # find the .xo file: were we successful? + 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 + return # something went wrong. + # hand off to journal os.chmod(app_temp, 0755) jobject = datastore.create() metadata = { @@ -806,13 +551,12 @@ class PippyActivity(ViewSourceActivity, groupthink.sugar_tools.GroupActivity): 'mime_type': 'application/vnd.olpc-sugar', } for k, v in metadata.items(): - # The dict.update method is missing =( - jobject.metadata[k] = v + jobject.metadata[k] = v # the dict.update method is missing =( jobject.file_path = os.path.join(app_temp, bundle_file[0]) datastore.write(jobject) - self._vte.feed('\r\n') - self._vte.feed(_('Activity saved to journal.')) - self._vte.feed('\r\n') + self._vte.feed("\r\n") + self._vte.feed(_("Activity saved to journal.")) + self._vte.feed("\r\n") self.journal_show_object(jobject.object_id) jobject.destroy() finally: @@ -821,152 +565,120 @@ 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') + if response_id is gtk.RESPONSE_OK: + 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']) + self.model.set_value(_iter, 1, entry["name"]) + def save_to_journal(self, file_path, cloudstring): _file = open(file_path, 'w') - if not self.shared_activity: - data = self.source_tabs.get_all_data() - zipped_data = zip(data[0], data[1]) - sessionlist = [] - app_temp = os.path.join(self.get_activity_root(), 'instance') - tmpfile = os.path.join(app_temp, - 'pippy-tempfile-storing.py') - for zipdata, dsid in map(None, zipped_data, self.session_data): - name, content = zipdata - - if dsid is not None: - dsitem = datastore.get(dsid) - __file = open(tmpfile, 'w') - __file.write(content) - __file.close() - dsitem.set_file_path(tmpfile) - dsitem.metadata['title'] = name - datastore.write(dsitem) - else: - dsobject = datastore.create() - dsobject.metadata['mime_type'] = 'text/x-python' - dsobject.metadata['title'] = name - __file = open(tmpfile, 'w') - __file.write(content) - __file.close() - dsobject.set_file_path(tmpfile) - datastore.write(dsobject) - dsitem = None - - if dsitem is not None: - sessionlist.append([name, dsitem.object_id]) - else: - sessionlist.append([name, dsobject.object_id]) - - self.metadata['mime_type'] = 'application/json' - _file.write(json.dumps(sessionlist)) + if not self._shared_activity: + self.metadata['mime_type'] = 'text/x-python' + global text_buffer + start, end = text_buffer.get_bounds() + text = text_buffer.get_text(start, end) + _file.write(text) else: self.metadata['mime_type'] = groupthink_mimetype _file.write(cloudstring) def load_from_journal(self, file_path): if self.metadata['mime_type'] == 'text/x-python': -<<<<<<< HEAD text = open(file_path).read() - # Discard the '#!/usr/bin/python' and 'coding: utf-8' lines, - # if present. -======= - try: - text = open(file_path).read() - except: - alert = NotifyAlert(10) - alert.props.title = _('Error') - alert.props.msg = _('Error reading data.') - - def remove_alert(alert, response_id): - self.remove_alert(alert) - - alert.connect("response", remove_alert) - self.add_alert(alert) - return - # discard the '#!/usr/bin/python' and 'coding: utf-8' lines, # if present ->>>>>>> 3ee39682ad9bc3daf6c67b95b9c8acb42b995d4d text = re.sub(r'^' + re.escape(PYTHON_PREFIX), '', text) - - self.initial_text_buffer = text - self.initial_title = self.metadata['title'] - self.loaded_from_journal = self.py_file = True - - elif self.metadata['mime_type'] == 'application/json': - data = json.loads(open(file_path).read()) - for name, dsid in data: - dsitem = datastore.get(dsid) - content = open(dsitem.get_file_path()).read() - self.loaded_session.append([name, content]) - self.session_data.append(dsitem.object_id) - + global text_buffer + text_buffer.set_text(text) elif self.metadata['mime_type'] == groupthink_mimetype: return open(file_path).read() ############# TEMPLATES AND INLINE FILES ############## -ACTIVITY_INFO_TEMPLATE = ''' +ACTIVITY_INFO_TEMPLATE = """ [Activity] name = %(title)s bundle_id = %(bundle_id)s -exec = sugar-activity %(class)s +service_name = %(bundle_id)s +class = %(class)s icon = activity-icon activity_version = %(version)d mime_types = %(mime_types)s show_launcher = yes %(extra_info)s -''' +""" PIPPY_ICON = \ -""" - -]> - - - - +""" + +]> + + + - """ +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.''' + """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.''' + """Returns a map of 'extra' files which should be included in the + generated activity bundle.""" # Cheat here and generate the map from the fs contents. extra = {} bp = get_bundle_path() @@ -975,101 +687,93 @@ def pippy_activity_extra_files(): for name in files: fn = os.path.join(root, name).replace(bp + '/', '') extra[fn] = open(os.path.join(root, name), 'r').read() + extra['activity/activity-default.svg'] = PIPPY_DEFAULT_ICON return extra def pippy_activity_news(): - '''Return the NEWS file for this activity.''' + """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 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 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 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 the mime types handled by the generated activity, as a list.""" return ['text/x-python', groupthink_mimetype] def pippy_activity_extra_info(): - return ''' + return """ license = GPLv2+ -update_url = http://activities.sugarlabs.org ''' +update_url = http://activities.sugarlabs.org """ ################# ACTIVITY BUNDLER ################ def main(): - '''Create a bundle from a pippy-style source file''' + """Create a bundle from a pippy-style source file""" from optparse import OptionParser from pyclbr import readmodule_ex from tempfile import mkdtemp from shutil import copytree, copy2, rmtree - from sugar3.activity import bundlebuilder - - parser = OptionParser(usage='%prog [options] [title] [sourcefile] [icon]') + from sugar import profile + from sugar.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.') parser.add_option('-p', '--pythonpath', dest='path', action='append', default=[], metavar='DIR', help='Append directory to python search path.') - (options, args) = parser.parse_args() - if len(args) < 3: - parser.error('The title, sourcefile and icon arguments are required.') - + if len(args) != 2: + parser.error('The title and sourcefile arguments are required.') title = args[0] sourcefile = args[1] - icon_path = args[2] 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 + # first take a gander at the source file and see if it's got extra info # for us. sourcedir, basename = os.path.split(sourcefile) if not sourcedir: sourcedir = '.' module, ext = os.path.splitext(basename) - f = open(icon_path, 'r') - icon = f.read() - f.close() - # Things we look for: + # things we look for: bundle_info = { 'version': 1, 'extra_files': {}, 'news': 'No news.', - 'icon': icon, + 'icon': PIPPY_DEFAULT_ICON, 'class': 'activity.VteActivity', - 'bundle_id': ('org.sugarlabs.pippy.%s%d' % - (generate_unique_id(), - int(round(uniform(1000, 9999), 0)))), + 'bundle_id': ('org.laptop.pippy.%s' % pytitle), 'mime_types': '', 'extra_info': '', } - # Are any of these things in the module? + # 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 if p_a_func in info: try_import = True if try_import: - # Yes, let's try to execute them to get better info about our bundle + # yes, let's try to execute them to get better info about our bundle oldpath = list(sys.path) sys.path[0:0] = [sourcedir] + options.path modobj = __import__(module) @@ -1079,9 +783,9 @@ def main(): bundle_info[func] = modobj.__dict__[p_a_func]() sys.path = oldpath - # Okay! We've done the hard part. Now let's build a bundle. - # Create a new temp dir in which to create the bundle. - app_temp = mkdtemp('.activity', 'Pippy') # Hope TMPDIR is set correctly! + # okay! We've done the hard part. Now let's build a bundle. + # create a new temp dir in which to create the bundle. + app_temp = mkdtemp('.activity', 'Pippy') # hope TMPDIR is set correctly! bundle = get_bundle_path() try: copytree('%s/library' % bundle, '%s/library' % app_temp) @@ -1105,36 +809,39 @@ def main(): os.makedirs(dirname) with open(os.path.join(dirname, filename), 'w') as f: f.write(contents) - # Put script into $app_temp/pippy_app.py + # put script into $app_temp/pippy_app.py copy2(sourcefile, '%s/pippy_app.py' % app_temp) - # Invoke bundle builder + # 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. - 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) + # 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'])) finally: rmtree(app_temp, ignore_errors=True) - print('Finally\r\n') if __name__ == '__main__': - import sys from gettext import gettext as _ - if False: # Change this to True to test within Pippy + import sys + 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