Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pydebug.py.bk
diff options
context:
space:
mode:
authorroot <root@ghunt-desktop.(none)>2010-04-23 17:53:01 (GMT)
committer root <root@ghunt-desktop.(none)>2010-04-23 17:53:01 (GMT)
commit91384302ef04ee915a9a80f9efa0215836975473 (patch)
tree78c330a1091ce2ef82f48f51357790b42fde5a6f /pydebug.py.bk
parent0378b3d4fb15f29752431b7477b69091797dfb74 (diff)
second try to get git to track the files I care about
Diffstat (limited to 'pydebug.py.bk')
-rw-r--r--pydebug.py.bk1856
1 files changed, 1856 insertions, 0 deletions
diff --git a/pydebug.py.bk b/pydebug.py.bk
new file mode 100644
index 0000000..d0d48cc
--- /dev/null
+++ b/pydebug.py.bk
@@ -0,0 +1,1856 @@
+# Copyright (C) 2009, George Hunt <georgejhunt@gmail.com>
+# Copyright (C) 2009, 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+from __future__ import with_statement
+import os, os.path, simplejson, ConfigParser, shutil, sys
+from subprocess import Popen, PIPE
+
+from gettext import gettext as _
+
+#major packages
+import gtk
+import gtk.glade
+import vte
+import pango
+#import gconf
+#import glib
+import pickle
+import hashlib
+import time
+#import gio
+import datetime
+import gobject
+
+#sugar stuff
+from sugar.graphics.toolbutton import ToolButton
+import sugar.graphics.toolbutton
+
+import sugar.env
+from sugar.graphics.xocolor import XoColor
+from sugar.graphics.icon import Icon
+from sugar.graphics.objectchooser import ObjectChooser
+from sugar.datastore import datastore
+from sugar.graphics.alert import *
+import sugar.activity.bundlebuilder as bundlebuilder
+from sugar.bundle.activitybundle import ActivityBundle
+from sugar.activity import activityfactory
+#from jarabe.model import shell
+
+#application stuff
+from terminal_pd import Terminal
+#public api for ipython
+
+#from IPython.core import ipapi 0.11 requires this
+import IPython.ipapi
+
+#from sourceview import SourceViewPd
+import sourceview_editor
+from sugar.activity.activity import Activity
+from help_pd import Help
+
+#following taken from Rpyc module
+#import Rpyc
+from Rpyc.Utils.Serving import start_threaded_server, DEFAULT_PORT
+from Rpyc.Connection import *
+from Rpyc.Stream import *
+import select
+from filetree import FileTree
+from datastoretree import DataStoreTree
+import pytoolbar
+#from pytoolbar import ActivityToolBox
+
+import logging
+from pydebug_logging import _logger, log_environment
+
+MASKED_ENVIRONMENT = [
+ 'DBUS_SESSION_BUS_ADDRESS',
+ 'PPID'
+]
+#PANES = ['TERMINAL','EDITOR','CHILD','PROJECT','HELP']
+PANES = ['TERMINAL','EDITOR','PROJECT','HELP']
+
+#colors for the playpen side of the project page
+PROJECT_FG = '#990000'
+PROJECT_BASE = "#fdd99b"
+PROJECT_BG = '#FFFFCC'
+
+#global module variable communicates to debugged programs
+pydebug_instance = None
+
+#following options taken from Develop_App
+class Options:
+ def __init__(self, template = None, **kw):
+ if template:
+ self.__dict__ = template.__dict__.copy()
+ else:
+ self.__dict__ = {}
+ self.__dict__.update(kw)
+
+class SearchOptions(Options):
+ pass
+S_WHERE = sourceview_editor.S_WHERE
+
+class PyDebugActivity(Activity,Terminal):
+ MIME_TYPE = 'application/vnd.olpc-sugar'
+ DEPRECATED_MIME_TYPE = 'application/vnd.olpc-x-sugar'
+ _zipped_extension = '.xo'
+ _unzipped_extension = '.activity'
+ dirty = False
+
+ def __init__(self, handle):
+ #handle object contains command line inputs to this activity
+ self.handle = handle
+ _logger.debug('Activity id:%s.Object id: %s. uri:%s'%(handle.activity_id,
+ handle.object_id, handle.uri))
+ if handle.object_id and handle.object_id != '':
+ self.passed_in_ds_object = datastore.get(handle.object_id)
+ debugstr = ''
+ if self.passed_in_ds_object:
+ for key in self.passed_in_ds_object.metadata.keys():
+ if key == 'preview': continue
+ debugstr += key + ':'+str(self.passed_in_ds_object.metadata[key]) + ', '
+ _logger.debug('initial datastore metadata dictionary==>: %r'%debugstr)
+
+ #Save a global poiinter so remote procedure calls can communicate with pydebug
+ global pydebug_instance
+ pydebug_instance = self
+
+ #init variables
+ self.make_paths()
+ self.save_icon_clicked = False
+ self.source_directory = None
+ self.data_file = None
+ self.help = None
+ self.help_x11 = None
+ self.project_dirty = False
+ self.sock = None
+ self.last_filename = None
+ self.debug_dict = {}
+ self.activity_dict = {}
+ self.file_pane_is_activities = False
+ self.manifest_treeview = None #set up to recognize an re-display of playpen
+ self.manifest_class = None
+ #self.set_title(_('PyDebug Activity'))
+ self.ds = None #datastore pointer
+ self._logger = _logger
+ self.traceback = 'Context'
+ self.abandon_changes = False
+ self.journal_class = None
+ self.delete_after_load = None
+ self.find_window = None
+ self.passed_in_db_object = None
+
+ # init the Classes we are subclassing
+ Activity.__init__(self, handle, create_jobject = False)
+ #Terminal has no needs for init
+ #Help.__init__(self,self)
+
+ # setup the search options
+ self.s_opts = SearchOptions(where = S_WHERE.multifile,
+ use_regex = False,
+ ignore_caps = True,
+ replace_all = False,
+
+ #defaults to avoid creating
+ #a new SearchOptions object for normal searches
+ #should never be changed, just make a copy like:
+ #SearchOptions(self.s_opts, forward=False)
+ forward = True,
+ stay = False
+ )
+ self.safe_to_replace = False
+
+
+ #set up the PANES for the different functions of the debugger
+ self.canvas_list = []
+ self.panes = {}
+ pane_index = 0
+ pane_index = self.new_pane(self._get_terminal_canvas,pane_index)
+ pane_index = self.new_pane(self._get_edit_canvas,pane_index)
+ #pane_index = self.new_pane(self._get_child_canvas,pane_index)
+ pane_index = self.new_pane(self._get_project_canvas,pane_index)
+ pane_index = self.new_pane(self._get_help_canvas,pane_index)
+
+ nb = gtk.Notebook()
+ nb.show()
+ nb.set_show_tabs(False)
+
+ for c in self.canvas_list:
+ nb.append_page(c)
+
+ self.pydebug_notebook = nb
+ #the following call to the activity code puts our notebook under the stock toolbar
+ self.set_canvas(nb)
+
+ #set up tool box/menu buttons
+ self.toolbox = pytoolbar.ActivityToolbox(self)
+ self.toolbox.connect_after('current_toolbar_changed',self._toolbar_changed_cb)
+
+ activity_toolbar = self.toolbox.get_activity_toolbar()
+ activity_toolbar.share.props.visible = True
+ #activity_toolbar.keep.props.visible = True
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ activity_toolbar.insert(separator, 0)
+
+ activity_go = ToolButton()
+ activity_go.set_stock_id('gtk-media-forward')
+ activity_go.set_icon_widget(None)
+ activity_go.set_tooltip(_('Start Debugging'))
+ activity_go.connect('clicked', self.project_run_cb)
+ #activity_go.props.accelerator = '<Ctrl>O'
+ activity_go.show()
+ activity_toolbar.insert(activity_go, 0)
+
+
+ activity_copy_tb = ToolButton('edit-copy')
+ activity_copy_tb.set_tooltip(_('Copy'))
+ activity_copy_tb.connect('clicked', self._copy_cb)
+ #activity_copy_tb.props.accelerator = '<Ctrl>C'
+ activity_toolbar.insert(activity_copy_tb, 3)
+ activity_copy_tb.show()
+
+ activity_paste_tb = ToolButton('edit-paste')
+ activity_paste_tb.set_tooltip(_('Paste'))
+ activity_paste_tb.connect('clicked', self._paste_cb)
+ #activity_paste_tb.props.accelerator = '<Ctrl>V'
+ activity_toolbar.insert(activity_paste_tb, 4)
+ activity_paste_tb.show()
+
+ activity_tab_tb = sugar.graphics.toolbutton.ToolButton('list-add')
+ activity_tab_tb.set_tooltip(_("Open New Tab"))
+ activity_tab_tb.props.accelerator = '<Ctrl>T'
+ activity_tab_tb.show()
+ activity_tab_tb.connect('clicked', self._open_tab_cb)
+ activity_toolbar.insert(activity_tab_tb, 5)
+
+ activity_tab_delete_tv = sugar.graphics.toolbutton.ToolButton('list-remove')
+ activity_tab_delete_tv.set_tooltip(_("Close Tab"))
+ activity_tab_delete_tv.props.accelerator = '<Ctrl><Shift>X'
+ activity_tab_delete_tv.show()
+ activity_tab_delete_tv.connect('clicked', self._close_tab_cb)
+ activity_toolbar.insert(activity_tab_delete_tv, 6)
+
+
+ activity_fullscreen_tb = sugar.graphics.toolbutton.ToolButton('view-fullscreen')
+ activity_fullscreen_tb.set_tooltip(_("Fullscreen"))
+ activity_fullscreen_tb.props.accelerator = '<Alt>Enter'
+ activity_fullscreen_tb.connect('clicked', self._fullscreen_cb)
+ activity_toolbar.insert(activity_fullscreen_tb, 7)
+ activity_fullscreen_tb.hide()
+
+ #Add editor functionality to the debugger
+ editbar = gtk.Toolbar()
+
+ editopen = ToolButton()
+ editopen.set_stock_id('gtk-new')
+ editopen.set_icon_widget(None)
+ editopen.set_tooltip(_('New File'))
+ editopen.connect('clicked', self._new_file_cb)
+ #editopen.props.accelerator = '<Ctrl>O'
+ editopen.show()
+ editbar.insert(editopen, -1)
+
+ editfile = ToolButton()
+ editfile.set_stock_id('gtk-open')
+ editfile.set_icon_widget(None)
+ editfile.set_tooltip(_('Open File'))
+ editfile.connect('clicked', self._read_file_cb)
+ editfile.props.accelerator = '<Ctrl>O'
+ editfile.show()
+ editbar.insert(editfile, -1)
+
+ editsave = ToolButton()
+ editsave.set_stock_id('gtk-save')
+ editsave.set_icon_widget(None)
+ editsave.set_tooltip(_('Save File'))
+ editsave.props.accelerator = '<Ctrl>S'
+ editsave.connect('clicked', self.save_cb)
+ editsave.show()
+ editbar.insert(editsave, -1)
+
+ editsaveas = ToolButton()
+ editsaveas.set_stock_id('gtk-save-as')
+ editsaveas.set_icon_widget(None)
+ editsaveas.set_tooltip(_('Save As'))
+ #editsaveas.props.accelerator = '<Ctrl>S'
+ editsaveas.connect('clicked', self.save_file_cb)
+ editsaveas.show()
+ editbar.insert(editsaveas, -1)
+
+
+ """
+ editjournal = ToolButton(tooltip=_('Open Journal'))
+ client = gconf.client_get_default()
+ color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ journal_icon = Icon(icon_name='document-save', xo_color=color)
+ editjournal.set_icon_widget(journal_icon)
+ editjournal.connect('clicked', self._show_journal_object_picker_cb)
+ editjournal.props.accelerator = '<Ctrl>J'
+ editjournal.show()
+ editbar.insert(editjournal, -1)
+ """
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ editundo = ToolButton('undo')
+ editundo.set_tooltip(_('Undo'))
+ editundo.connect('clicked', self.editor.undo)
+ editundo.props.accelerator = '<Ctrl>Z'
+ editundo.show()
+ editbar.insert(editundo, -1)
+
+ editredo = ToolButton('redo')
+ editredo.set_tooltip(_('Redo'))
+ editredo.connect('clicked', self.editor.redo)
+ editredo.props.accelerator = '<Ctrl>Y'
+ editredo.show()
+ editbar.insert(editredo, -1)
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ editcut = ToolButton()
+ editcut.set_stock_id('gtk-cut')
+ editcut.set_icon_widget(None)
+ editcut.set_tooltip(_('Cut'))
+ self.edit_cut_handler_id = editcut.connect('clicked', self.editor.cut)
+ editcut.props.accelerator = '<Ctrl>X'
+ editbar.insert(editcut, -1)
+ editcut.show()
+
+ editcopy = ToolButton('edit-copy')
+ editcopy.set_tooltip(_('Copy'))
+ self.edit_copy_handler_id = editcopy.connect('clicked', self.editor.copy)
+ editcopy.props.accelerator = '<Ctrl>C'
+ editbar.insert(editcopy, -1)
+ editcopy.show()
+
+ editpaste = ToolButton('edit-paste')
+ editpaste.set_tooltip(_('Paste'))
+ self.edit_paste_handler_id = editpaste.connect('clicked', self.editor.paste)
+ editpaste.props.accelerator = '<Ctrl>V'
+ editpaste.show()
+ editbar.insert(editpaste, -1)
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ editfind = ToolButton('viewmag1')
+ editfind.set_tooltip(_('Find and Replace'))
+ editfind.connect('clicked', self.show_find)
+ editfind.props.accelerator = '<Ctrl>F'
+ editfind.show()
+ editbar.insert(editfind, -1)
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(True)
+ separator.show()
+ editbar.insert(separator, -1)
+
+ self.zoomout = ToolButton('zoom-out')
+ self.zoomout.set_tooltip(_('Zoom out'))
+ self.zoomout.connect('clicked', self.__zoomout_clicked_cb)
+ editbar.insert(self.zoomout, -1)
+ self.zoomout.show()
+
+ self.zoomin = ToolButton('zoom-in')
+ self.zoomin.set_tooltip(_('Zoom in'))
+ self.zoomin.connect('clicked', self.__zoomin_clicked_cb)
+ editbar.insert(self.zoomin, -1)
+ self.zoomin.show()
+
+ editbar.show_all()
+ self.toolbox.add_toolbar(_('Edit'), editbar)
+
+ #childbar = gtk.Toolbar()
+ #childbar.show_all()
+ #self.toolbox.add_toolbar(_('Your Program'), childbar)
+
+ project_run = ToolButton()
+ project_run.set_stock_id('gtk-media-forward')
+ project_run.set_icon_widget(None)
+ project_run.set_tooltip(_('Start Debugging'))
+ project_run.connect('clicked', self.project_run_cb)
+ #project_run.props.accelerator = '<Ctrl>C'
+ project_run.show()
+
+ separator = gtk.SeparatorToolItem()
+ separator.set_draw(False)
+ separator.set_expand(True)
+ separator.show()
+
+ self.keep = ToolButton(tooltip=_('Save Snapshot of the program in the Playpen to the Journal'))
+ #client = gconf.client_get_default()
+ #color = XoColor(client.get_string('/desktop/sugar/user/color'))
+ #keep_icon = Icon(icon_name='document-save', xo_color=color)
+ keep_icon = Icon(icon_name='document-save')
+ self.keep.set_icon_widget(keep_icon)
+ keep_icon.show()
+ #self.keep.props.accelerator = '<Ctrl>S'
+ self.keep.connect('clicked', self.__keep_clicked_cb)
+ #self.insert(self.keep, -1)
+ self.keep.show()
+
+ projectbar = gtk.Toolbar()
+ projectbar.show_all()
+ projectbar.insert(project_run, -1)
+ projectbar.insert(separator, -1)
+ projectbar.insert(self.keep,-1)
+ self.toolbox.add_toolbar(_('Project'), projectbar)
+
+ self.help = Help(self)
+ helpbar = self.help.get_help_toolbar()
+ self.toolbox.add_toolbar(_('Help'), helpbar)
+
+
+ self.set_toolbox(self.toolbox)
+ self.toolbox.show()
+
+ #get the persistent data across all debug sessions
+ self.get_config ()
+
+ #set the default contents for edit
+ self.font_size = self.debug_dict.get('font_size',8)
+
+ #get the journal datastore information and resume previous activity
+ #self.metadata = self.ds
+ if self.passed_in_ds_object and self.passed_in_ds_object.get_file_path():
+ ds_file = self.passed_in_ds_object.get_file_path()
+ else:
+ ds_file = ''
+ self.read_file(ds_file)
+
+ #set which PANE is visible initially
+ self.set_visible_canvas(self.panes['PROJECT'])
+ self.set_toolbar(self.panes['PROJECT'])
+ self.non_blocking_server()
+ #glib.idle_add(self.non_blocking_server)
+ self.setup_project_page()
+ _logger.debug('child path for program to be debugged is %r\nUser Id:%s'%(self.child_path,os.geteuid()))
+
+ #create the terminal tabs, start up the socket between 1st and 2nd terminal instances
+ self.setup_terminal()
+
+
+ def __stop_clicked_cb(self,button):
+ _logger('caught stop clicked call back')
+ self.close(skip_save = True)
+
+ def __zoomin_clicked_cb(self,button):
+ self.font_size += 1
+ self.editor.change_font_size(self.font_size)
+ self.debug_dict['font_size'] = self.font_size
+
+ def __zoomout_clicked_cb(self,botton):
+ self.font_size -= 1
+ self.editor.change_font_size(self.font_size)
+ self.debug_dict['font_size'] = self.font_size
+
+ def command_line(self,cmd, alert_error=True):
+ _logger.debug('command_line cmd:%s'%cmd)
+ p1 = Popen(cmd,stdout=PIPE, shell=True)
+ output = p1.communicate()
+ if p1.returncode != 0 :
+ _logger.debug('error returned from shell command: %s was %s'%(cmd,output[0]))
+ if alert_error: self.alert(_('%s Command returned non zero\n'%cmd+output[0]))
+ return output[0],p1.returncode
+
+ def sugar_version(self):
+ cmd = '/bin/rpm -q sugar'
+ reply = self.command_line(cmd)
+ if reply and reply[0].find('sugar') > -1:
+ version = reply.split('-')[1]
+ version_chunks = version.split('.')
+ major_minor = version_chunks[0] + '.' + version_chunks[1]
+ return float(major_minor)
+ return None
+
+ def non_blocking_server(self):
+ start_threaded_server()
+
+ def new_pane(self,funct,i):
+ self.panes[PANES[i]] = i
+ self.canvas_list.append(funct())
+ i += 1
+ return i
+
+ def make_paths(self):
+ self.pydebug_path = os.environ['SUGAR_BUNDLE_PATH']
+ p_path = os.environ['SUGAR_BUNDLE_PATH']
+ if not os.environ.get("PYTHONPATH",'') == '':
+ p_path = p_path + ':'
+ os.environ['PYTHONPATH'] = p_path + os.environ.get("PYTHONPATH",'')
+ _logger.debug('sugar_bundle_path:%s\nsugar_activity_root:%s'%(os.environ['SUGAR_BUNDLE_PATH'],
+ os.environ['SUGAR_ACTIVITY_ROOT']))
+ self.debugger_home = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data')
+ self.child_path = None
+ os.environ["HOME"]=self.debugger_home
+ os.environ['PATH'] = os.path.join(self.pydebug_path,'bin:') + os.environ['PATH']
+ self.storage = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data/pydebug')
+ self.sugar_bundle_path = os.environ['SUGAR_BUNDLE_PATH']
+ self.activity_playpen = os.path.join(self.storage,'playpen')
+ if not os.path.isdir(self.activity_playpen):
+ os.makedirs(self.activity_playpen)
+
+ def _get_edit_canvas(self):
+ self.editor = sourceview_editor.GtkSourceview2Editor(self)
+ return self.editor
+
+ def setup_terminal(self):
+ os.environ['IPYTHONDIR'] = self.pydebug_path
+ _logger.debug('Set IPYTHONDIR to %s'%self.pydebug_path)
+ self._create_tab({'cwd':self.sugar_bundle_path})
+ self._create_tab({'cwd':self.sugar_bundle_path})
+ #start the debugger user interface
+ alias_cmd = 'alias go="%s"\n'%('./bin/ipython.py',)
+ self.feed_virtual_terminal(0,alias_cmd)
+
+ self.feed_virtual_terminal(0,'./bin/ipython.py \n')
+ #cmd = 'run ' + os.path.join(self.sugar_bundle_path,'bin','start_debug.py') + '\n'
+ #self.feed_virtual_terminal(0,cmd)
+
+
+ def start_debugging(self): #check for a start up script in bundle root or bundle_root/bin
+ command = self.activity_dict.get('command','')
+ if command == '':
+ self.alert('No Activity Loaded')
+ return
+ _logger.debug("Command to execute:%s."%command)
+ self.editor.save_all()
+
+ #try to restore a clean debugging environment
+ #self.feed_virtual_terminal(0,'quit()\r\n\r\n')
+
+ self.set_visible_canvas(self.panes['TERMINAL'])
+ #change the menus
+ self.toolbox.set_current_toolbar(self.panes['TERMINAL'])
+ message = _('\n\n Use the HELP in the Ipython interpreter to learn to DEBUG your program.\n')
+ self.message_terminal(0,message)
+ gr
+ #get the ipython shell object
+ """ this works but is not needed now
+ ip = ipapi.get()
+ arg_str = 'run -d -b %s %s'%(self.pydebug_path,self.child_path)
+ ip.user_ns['go'] = arg_str
+ _logger.debug('about to use "%s" to start ipython debugger\n'%(arg_str))
+ """
+ self.feed_virtual_terminal(0,'go\n')
+
+ def set_ipython_traceback(self):
+ pass
+ """
+ tb = self.debug_dict['traceback']
+ ip = IPython.ipapi.get()
+ ipmagic = ip.user_ns['ipmagic']
+ ipmagic('xmode ' + tb)
+ """
+
+ def find_import(self,fn):
+ _logger.debug('find_import in file %s'%fn)
+ try_fn = os.path.join(self.child_path,fn)
+ if not os.path.isfile(try_fn):
+ try_fn += '.py'
+ if not os.path.isfile(try_fn):
+ _logger.debug('in find_import, failed to find file %s'%try_fn)
+ return
+ line_no = 0
+ for line in open(try_fn,'r'):
+ if line.startswith('import'):
+ return line_no, try_fn
+ line_no += 1
+ return -1, None
+
+ def _get_child_canvas(self):
+ fr = gtk.Frame()
+ label = gtk.Label("This page will be replaced with the \noutput from your program")
+ label.show()
+ fr.add(label)
+ fr.show()
+ return fr
+
+
+ def _get_help_canvas(self):
+ fr = gtk.Frame()
+ label = gtk.Label(_("Loading Help Page"))
+ label.show()
+ fr.add(label)
+ fr.show()
+ return fr
+
+ def get_icon_pixbuf(self, stock):
+ return self.treeview.render_icon(stock_id=getattr(gtk, stock),
+ size=gtk.ICON_SIZE_MENU,
+ detail=None)
+
+
+ """
+ def _get_help_canvas(self):
+ fr = gtk.Frame() #FIXME explore whether frame is still needed--was to fix webview problem
+ fr.show()
+ nb = gtk.Notebook()
+ nb.show()
+ fr.add(nb)
+ nb.append_page(self.get_first_webview())
+ self.help_notebook = nb
+ return fr
+ """
+
+ def _child_cb(self,event):
+ pass
+
+ def _project_cb(self,event):
+ pass
+
+ #lots of state to change whenever one of the major tabs is clicked
+ def set_visible_canvas(self,index): #track the toolbox tab clicks
+ self.pydebug_notebook.set_current_page(index)
+ if index == self.panes['TERMINAL']:
+ gobject.idle_add(self.set_terminal_focus)
+ self.editor.save_all()
+ elif index == self.panes['HELP']:
+ self.help_selected()
+ elif index == self.panes['PROJECT'] and self.manifest_class:
+ self.manifest_class.set_file_sys_root(self.child_path)
+ self.current_pd_page = index
+ gobject.idle_add(self.grab_notebook_focus)
+
+ def grab_notebook_focus(self):
+ self.pydebug_notebook.grab_focus()
+ return False
+
+ def _toolbar_changed_cb(self,widget,tab_no):
+ _logger.debug('tool tab changed notification %d'%tab_no)
+ self.set_visible_canvas(tab_no)
+
+ def set_toolbar(self,page_no):
+ self.toolbox.set_current_toolbar(page_no)
+
+ def key_press_cb(self,widget,event):
+ state = event.get_state()
+ if state and gtk.gdk.SHIFT_MASK and gtk.gdk.CONTROL_MASK and gtk.gdk.MOD1_MASK == 0:
+ self.file_changed = True
+ #put a star in front of the filename
+ return False
+
+ ### following routines are copied from develop_app for use with sourceview_editor
+ def _replace_cb(self, button=None):
+ ftext = self._search_entry.props.text
+ rtext = self._replace_entry.props.text
+ _logger.debug('replace %s with %s usiing options %r'%(ftext,rtext,self.s_opts))
+ replaced, found = self.editor.replace(ftext, rtext,
+ self.s_opts)
+ if found:
+ self._replace_button.set_sensitive(True)
+
+ def _search_entry_activated_cb(self, entry):
+ text = self._search_entry.props.text
+ if text:
+ self._findnext_cb(None)
+
+ def _search_entry_changed_cb(self, entry):
+ self.safe_to_replace = False
+ text = self._search_entry.props.text
+ if not text:
+ self._findprev.set_sensitive(False)
+ self._findnext.set_sensitive(False)
+ else:
+ self._findprev.set_sensitive(True)
+ self._findnext.set_sensitive(True)
+ if not self.s_opts.use_regex: #do not do partial searches for regex
+ if self.editor.find_next(text,
+ SearchOptions(self.s_opts,
+ stay=True,
+ where=(self.s_opts.where if
+ self.s_opts.where != S_WHERE.multifile
+ else S_WHERE.file))):
+ #no multifile, or focus gets grabbed
+ self._replace_button.set_sensitive(True)
+
+ def _replace_entry_changed_cb(self, entry):
+ if self._replace_entry.props.text:
+ self.safe_to_replace = True
+
+ def _findprev_cb(self, button=None):
+ ftext = self._search_entry.props.text
+ if ftext:
+ if self.editor.find_next(ftext,
+ SearchOptions(self.s_opts,
+ forward=False)):
+ self._replace_button.set_sensitive(True)
+
+ def _findnext_cb(self, button=None):
+ ftext = self._search_entry.props.text
+ _logger.debug('find next %s'%ftext)
+ if ftext:
+ if self.editor.find_next(ftext, self.s_opts):
+ self._replace_button.set_sensitive(True)
+ self.editor.set_focus()
+
+
+ def show_find(self,button):
+ if not self.find_window:
+ self._find_width = 400
+ self._find_height = 300
+ self.find_window = self.wTree.get_widget("find")
+ self.find_window.connect('destroy',self.close_find_window)
+ self.find_window.connect('delete_event',self.close_find_window)
+ self.find_connect()
+ self.find_window.set_title(_('FIND OR REPLACE'))
+ self.find_window.set_size_request(self._find_width,self._find_height)
+ self.find_window.set_decorated(False)
+ self.find_window.set_resizable(False)
+ self.find_window.set_modal(False)
+ self.find_window.connect('size_request',self._size_request_cb)
+ self.find_window.show()
+
+ def _size_request_cb(self, widget, req):
+ x = gtk.gdk.screen_width() -self._find_width - 50
+ self.find_window._width = req.width
+ self.find_window._height = req.height
+ self.find_window.move(x,150)
+
+ def find_connect(self):
+ mdict = {
+ 'find_close_clicked_cb':self.close_find_window,
+ 'find_entry_changed_cb':self.find_entry_changed_cb,
+ 'replace_entry_changed_cb':self.replace_entry_changed_cb,
+ 'find_previous_clicked_cb':self._findprev_cb,
+ 'find_next_clicked_cb':self._findnext_cb,
+ 'find_entry_changed_cb':self._search_entry_changed_cb,
+ 'replace_entry_changed_cb':self._replace_entry_changed_cb,
+ 'replace_clicked_cb':self._replace_cb,
+ #'replace_all_clicked_cb':self._findprev_cb,
+ }
+ self.wTree.signal_autoconnect(mdict)
+ self._findnext = self.wTree.get_widget("find_next")
+ self._findprev = self.wTree.get_widget("find_previous")
+ self._search_entry = self.wTree.get_widget("find_entry")
+ self._replace_entry = self.wTree.get_widget("replace_entry")
+ self._replace_button = self.wTree.get_widget("replace")
+ #self.replace_all = self.wTree.get_widget("replace_all")
+ self.find_where = self.wTree.get_widget("find_where")
+
+
+ def close_find_window(self,button):
+ self.find_window.hide()
+ return True
+
+ def find_entry_changed_cb(self,button):
+ #self.editor.search_for =
+ pass
+ def replace_entry_changed_cb(self,button):
+ #self.editor.search_for =
+ pass
+
+ def project_run_cb(self,button):
+ _logger.debug('entered project_run_cb')
+ """
+ start_script = ['python','import sys','from Rpyc import *','from Rpyc.Utils import remote_interpreter',
+ 'c = SocketConnection("localhost")','remote_interpreter(c)']
+ for l in start_script:
+ self.feed_virtual_terminal(0,l+'\r\n')
+ """
+ self.start_debugging()
+
+ def __keep_clicked_cb(self, button):
+ self.write_binary_to_datastore(None)
+
+
+ ###### SUGAR defined read and write routines -- do not let them overwrite what's being debugged
+
+ def read_file(self, file_path):
+ """
+ If the ds_object passed to PyDebug is the last one saved, then just assume that the playpen is valid.
+ If the ds_object is not the most recent one, try to load the playpen with the contents referenced by the git_id
+ (reading the wiki, I discover we cannot count on metadata -- so cancel the git_id scheme)
+ """
+ #keep our own copy of the metadata
+ self.activity_dict = self.metadata.copy()
+ debugstr = ''
+ for key in self.activity_dict.keys():
+ if key == 'preview': continue
+ debugstr += key + ':'+str(self.activity_dict[key]) + ', '
+ _logger.debug ('In read_file: activity dictionary==> %s'%debugstr)
+ if not self.debug_dict: self.get_config()
+ if self.activity_dict.get('uid','XxXxXx') == self.debug_dict.get('jobject_id','YyYyY'):
+ _logger.debug('pick up where we left off')
+ if self.activity_dict.get('child_path') and os.path.isdir(self.activity_dict.get('child_path')):
+ self.child_path = self.activity_dict['child_path']
+ self.setup_new_activity()
+ return
+ if self.activity_dict.has_key('git_id') and self.debug_dict['git_id'] != '':
+ os.chdir(self.activity_dict['git_home'])
+ cmd = 'git checkout %s'%self.activity_dict.get('git_id')
+ git_output = self.command_line(cmd)
+ if git_output[1]==0:
+ self.load_activity_to_playpen(self.activity_dict.get('git_home'))
+ return
+ #update the project display
+ if self.journal_class:
+ self.journal_class.new_directory()
+
+
+ def write_file(self, file_path):
+ """
+ The paradigm designed into the XO, ie an automatic load from the Journal at activity startup
+ does not make sense during a debugging session. An errant stack overflow can easily crash
+ the system and require a reboot. For the session manager to overwrite the changes that are stored
+ on disk, but not yet saved in the journal is highly undesireable. So we'll let the user save to
+ the journal, and perhaps optionally to the sd card (because it is removable, should the system die)
+ """
+ if self.save_icon_clicked == True: #this was a specific request to save a commit to git
+ self.save_icon_clicked = False
+ _logger.debug('saving current playpen contents')
+ alert = self.alert(_('Saving current Activity to Home Directory'))
+ self.to_home_clicked_cb(None) #copies playpen and sets self._to_home_dest
+ if alert: self.remove_alert(alert)
+ alert = self.alert(_('Copying changes to GIT repository'))
+ git_id = self.do_git_commit(self._to_home_dest)
+ if alert: self.remove_alert(alert)
+ if git_id:
+ self.alert(_('GIT commit successful. ID:%s')%git_id)
+ self._jobject.metadata['commit_id'] = git_id
+ self._jobject.metadata['git_home'] = self._to_home_dest
+ today = datetime.date.today()
+ self._jobject.metadata['title'] = self.activity_dict['name'] +' GIT-'+ git_id #self.activity_dict.get('commit_text',today)
+ datastore.write(self._jobject)
+ self._jobject.destroy()
+ #get a new dsobject
+ self.debug_dict['jobject_id'] = str(self.get_new_dsobject())
+ self._jobject = self.debug_dict['jobject_id']
+ else:
+ alert = self.alert(_('GIT repository unchanged. File Tree is unchanged from previous COMMIT'))
+ jid = self.debug_dict.get('jobject_id','')
+ _logger.debug('write file debug-dict.jobject_id: %s. Jobject passed to write:%s'%(jid,self.metadata.get('uid','')))
+ chunk = self.activity_dict.get('name','')
+ self._jobject.metadata['title'] = 'PyDebug_' + chunk
+ self._jobject.metadata['activity'] = 'org.laptop.PyDebug'
+ self._jobject.metadata['version'] = self.activity_dict.get('version','')
+ self._jobject.metadata['name'] = self.activity_dict.get('name','')
+ self._jobject.metadata['bundle_id'] = self.activity_dict.get('bundle_id','')
+ self._jobject.metadata['icon'] = self.activity_dict.get('icon','')
+ self._jobject.metadata['child_path'] = self.child_path
+
+ datastore.write(self._jobject)
+ self.write_activity_info()
+ self.put_config()
+ return
+
+ def do_git_commit(self, tree):
+ """ First check the status of the source tree, if it is modified, do a commit, and store the
+ commit id in the metadata.
+ Input: path of the source tree
+ Returns: Commit id or None if there is an error
+ """
+ os.chdir(tree)
+ if not os.path.isdir(os.path.join(tree,'.git')):
+ cmd = 'git init'
+ cmd_output = self.command_line(cmd, alert_error=False)
+ cmd = 'git add *'
+ cmd_output = self.command_line(cmd, alert_error=False)
+ cmd = 'git status'
+ cmd_output = self.command_line(cmd, alert_error=False)
+ do_commit = False
+ if cmd_output[0]:
+ for line in cmd_output[0].split('\n'):
+ if line.find('modified') > -1: do_commit = True
+ if line.find('new file:') > -1: do_commit = True
+ if not do_commit:
+ _logger.debug('git did not commit because no unmodified files were detected')
+ return None #there have been no changes to write to library
+ today = datetime.date.today()
+ commit_message = self.activity_dict.get('commit_text',today)
+ cmd = 'git commit -a -m "%s"'%commit_message
+ cmd_output = self.command_line(cmd)
+ git_id = None
+ if not cmd_output[1]!=0:
+ _logger.debug('git commit returned no error')
+ return None
+ _logger.debug('git commit response:%s'%cmd_output)
+ for line in cmd_output.split('\n'):
+ chunks = line.split()
+ if len(chunks) < 2: continue
+ if chunks[0] == '[master':
+ if chunks[1][:-1] == ']':
+ git_id = chunks[1][:-1]
+ if len(chunks) < 3: continue
+ if chunks[2][:-1] == ']':
+ git_id = chunks[2][:-1]
+ if not git_id: return None
+ self.activity_dict['git_id'] = git_id
+ return git_id
+
+ def write_binary_to_datastore(self):
+ """
+ Check to see if there is a child loaded.
+ #Then copy the home directory data for this application into the bundle
+ then bundle it up and write it to the journal
+ lastly serialize the project information and write it to the journal
+
+
+ --fixme create an "untitled.activity" directory when child path is none and get rid of following check:
+ _logger.debug('Entered write_binary_to_datastore with child_path:%s'%self.child_path)
+ if not (os.path.isdir(self.child_path) and self.child_path.split('.')[-1:][0] == 'activity'):
+ self.alert(_('No Program loaded'))
+ return
+ """
+
+
+ """
+ fixme get rid of home directory management
+ #copy the home directory config stuff into the bundle
+ home_dir = os.path.join(self.child_path,'HOME')
+ try:
+ os.rmtree(home_dir)
+ except:
+ pass
+ try:
+ os.mkdir(home_dir)
+ except:
+ pass
+ source = self.debugger_home
+ dest = os.path.join(self.child_path,'HOME')
+ _logger.debug('writing HOME info from %s to %s.'%(source,dest))
+ for f in os.listdir(self.debugger_home):
+ if f == '.': continue
+ if f == '..': continue
+ if f == 'pydebug': continue
+ if f == '.sugar': continue
+ try:
+ if os.path.isdir(f):
+ shutil.copytree(f,dest)
+ else:
+ shutil.copy(f,dest)
+ except:
+ pass
+ """
+ dist_dir = os.path.join(self.child_path,'dist')
+ try:
+ os.rmtree(dist_dir)
+ except:
+ pass
+ try:
+ os.mkdir(dist_dir)
+ except:
+ pass
+ #create the manifest for the bundle
+ config = self.write_manifest()
+ do_tgz = True
+ #if manifest was successful, write the xo bundle to the instance directory
+ if config:
+ do_tgz = False
+ try:
+ #actually write the xo file
+ packager = bundlebuilder.XOPackager(bundlebuilder.Builder(config))
+ packager.package()
+ source = os.path.join(self.child_path,'dist',str(config.xo_name))
+ dest = os.path.join(self.get_activity_root(),'instance',str(config.xo_name))
+ _logger.debug('writing to the journal from %s to %s.'%(source,dest))
+ if os.path.isfile(dest):
+ os.unlink(dest)
+ try:
+ shutil.copy(source,dest)
+ package = config.xo_name
+ except IOError:
+ _logger.debug('shutil.copy error %d: %s. ',IOError[0],IOError[1])
+ do_tgz = True
+ except:
+ do_tgz = True
+ if do_tgz:
+ dest = self.just_do_tar_gz()
+ if dest:
+ package = os.path.basename(dest)
+ dsobject = datastore.create()
+ dsobject.metadata['package'] = package
+ dsobject.metadata['title'] = package
+ dsobject.metadata['mime_type'] = 'binary'
+ dsobject.metadata['activity'] = 'org.laptop.PyDebug'
+ dsobject.metadata['icon'] = self.debug_dict.get('icon','')
+ #calculate and store the new md5sum
+ self.debug_dict['tree_md5'] = self.md5sum_tree(self.child_path)
+ dsobject.metadata['tree_md5'] = self.debug_dict['tree_md5']
+ if dest: dsobject.set_file_path(dest)
+
+ #actually make the call which writes to the journal
+ try:
+ datastore.write(dsobject,transfer_ownership=True)
+ _logger.debug('succesfully wrote to the journal from %s.'%(dest))
+ except:
+ return
+ #update the project display
+ if self.journal_class:
+ self.journal_class.new_directory()
+
+ def write_manifest(self):
+ try:
+ os.remove(os.path.join(self.child_path,'MANIFEST'))
+ except:
+ pass
+ dest = self.child_path
+ _logger.debug('Writing manifest to %s.'%(dest))
+ try:
+ config = bundlebuilder.Config(dest)
+ b = bundlebuilder.Builder(config)
+ b.fix_manifest()
+ except:
+ _logger.debug('fix manifest error: ',sys.exc_type,sys.exc_info()[0],sys.exc_info()[1])
+ return None
+ return config
+
+ def just_do_tar_gz(self):
+ """
+ tar and compress the child_path tree to the journal
+ """
+ name = self.child_path.split('/')[-1].split(".")[0]+'.tar.gz'
+ os.chdir(self.activity_playpen)
+ dest = os.path.join(self.get_activity_root(),'instance',name)
+ cmd = 'tar czf %s %s'%(dest,'./'+os.path.basename(self.child_path))
+ ans = self.command_line(cmd)
+ _logger.debug('cmd:%s'%cmd)
+ if ans[1]!=0:
+ return None
+ return dest
+
+ def load_activity_to_playpen(self,file_path):
+ """loads from a disk tree"""
+ self._new_child_path = os.path.join(self.activity_playpen,os.path.basename(file_path))
+ _logger.debug('copying file for %s to %s'%(file_path,self._new_child_path))
+ self._load_playpen(file_path)
+
+ def try_to_load_from_journal(self,object_id):
+ """
+ loads a zipped XO or tar.gz application file (tar.gz if bundler cannot parse the activity.info file)
+ """
+ self.ds = datastore.get(object_id[0])
+ if not self.ds:
+ _logger.debug('failed to get datastore object with id:%s'%object_id[0])
+ return
+ dsdict=self.ds.get_metadata()
+ file_name_from_ds = self.ds.get_file_path()
+ project = dsdict.get('package','')
+ if not (project.endswith('.xo') or project.endswith('.tar.gz')):
+ self.alert(_('This journal item does not appear to be a zipped activity. Package:%s.'%project))
+ self.ds.destroy()
+ self.ds = None
+ return
+ filestat = os.stat(file_name_from_ds)
+ size = filestat.st_size
+ _logger.debug('In try_to_load_from_journal. Object_id %s. File_path %s. Size:%s'%(object_id[0], file_name_from_ds, size))
+ if project.endswith('.xo'):
+ try:
+ self._bundler = ActivityBundle(file_name_from_ds)
+ name = self._bundler.get_name()
+ iszip=True
+ istar = False
+ except:
+ self.alert('Error: Malformed Activity Bundle')
+ self.ds.destroy()
+ self.ds = None
+ return
+ else:
+ name = project.split('.')[0]
+ #self.delete_after_load = os.path.abspath(file_name_from_ds,name)
+ iszip = False
+ istar = True
+ self._new_child_path = os.path.join(self.activity_playpen,name+'.activity')
+ self._load_playpen(file_name_from_ds, iszip, istar)
+
+ def _load_playpen(self,source_fn, iszip = False, istar=False):
+ """entry point for both xo and file tree sources"""
+ self._load_to_playpen_source = source_fn
+ #if necessary clean up contents of playpen
+ if self.child_path and os.path.isdir(self.child_path):
+ self.abandon_changes = True
+ self.debug_dict['tree_md5'] = ''
+ self.debug_dict['child_path'] = ''
+ self.editor.remove_all()
+ if self.child_path:
+ shutil.rmtree(self.child_path)
+ self.abandon_changes = False
+ if self._load_to_playpen_source == None:
+ #having done the clearing, just stop
+ return
+ if iszip:
+ self._bundler.install(self.activity_playpen)
+ if self.ds: self.ds.destroy()
+ self.ds = None
+ elif istar:
+ dsdict = self.ds.get_metadata()
+ project = dsdict.get('package','dummy.tar.gz')
+ name = project.split('.')[0]
+ dest = os.path.join(self.activity_playpen,project)
+ shutil.copy(source_fn,dest)
+ os.chdir(self.activity_playpen)
+ cmd = 'tar zxf %s'%dest
+ _logger.debug('loading tar.gz with cmd %s'%cmd)
+ rtn = self.command_line(cmd)
+ if rtn[1] != 0: return
+ #os.unlink(dest)
+ if self.ds: self.ds.destroy()
+ self.ds = None
+ else:
+ if self.activity_playpen[-1] == '/':
+ dest = self.activity_playpen[:-1]
+ else:
+ dest = self.activity_playpen
+ os.chdir(self._load_to_playpen_source)
+ cmd = 'rsync -av %s %s'%(self._load_to_playpen_source,self.activity_playpen)
+ output = self.command_line(cmd)
+ if not output[1] == 0:
+ return
+ if self.delete_after_load:
+ shutil.rmtree(self.delete_after_load, ignore_errors=True)
+ self.debug_dict['source_tree'] = self._load_to_playpen_source
+ self.child_path = self._new_child_path
+ self.setup_new_activity()
+
+ def setup_new_activity(self):
+ _logger.debug('in setup_new_activity. child path before chdir:%s'%self.child_path)
+ if self.child_path == None:
+ return
+ os.chdir(self.child_path)
+ self.read_activity_info(self.child_path)
+ self.display_current_project()
+
+ #add the bin directory to path
+ os.environ['PATH'] = os.path.join(self.child_path,'bin') + ':' + os.environ['PATH']
+
+ #calculate and store the md5sum
+ self.debug_dict['tree_md5'] = self.md5sum_tree(self.child_path)
+
+ #find largest python files for editor
+ list = [f for f in os.listdir(self.child_path) if f[0] <> '.']
+ #list = self.manifest_class.get_filenames_list(self.child_path)
+ if not list: return
+ sizes = []
+ for f in list:
+ full_path = os.path.join(self.child_path,f)
+ if not f.endswith('.py'):continue
+ size = self.manifest_class.file_size(full_path)
+ sizes.append((size,full_path,))
+ #_logger.debug('python file "%s size %d'%(f,size))
+ for s,f in sorted(sizes,reverse=True)[:5]:
+ self.editor.load_object(f,os.path.basename(f))
+ self.editor.set_current_page(0)
+
+ ##################### ALERT ROUTINES ##################################
+
+ def alert(self,msg,title=None):
+ alert = NotifyAlert(10)
+ if title != None:
+ alert.props.title=_('There is no Activity file')
+ alert.props.msg = msg
+ alert.connect('response',self.no_file_cb)
+ self.add_alert(alert)
+ return alert
+
+ def no_file_cb(self,alert,response_id):
+ self.remove_alert(alert)
+
+ from sugar.graphics.alert import ConfirmationAlert
+
+ def confirmation_alert(self,msg,title=None,confirmation_cb = None):
+ alert = ConfirmationAlert()
+ alert.props.title=title
+ alert.props.msg = msg
+ alert.pydebug_cb = confirmation_cb
+ alert.connect('response', self._alert_response_cb)
+ self.add_alert(alert)
+ return alert
+
+ #### Method: _alert_response_cb, called when an alert object throws a
+ #response event.
+ def _alert_response_cb(self, alert, response_id):
+ #remove the alert from the screen, since either a response button
+ #was clicked or there was a timeout
+ this_alert = alert #keep a reference to it
+ self.remove_alert(alert)
+ #Do any work that is specific to the type of button clicked.
+ if response_id is gtk.RESPONSE_OK and this_alert.pydebug_cb != None:
+ this_alert.pydebug_cb (this_alert, response_id)
+
+ def _new_file_cb(self, widget):
+ full_path = self.non_conflicting(self.child_path,'Unsaved_Document.py')
+ self.editor.load_object(full_path,os.path.basename(full_path))
+
+ def _read_file_cb(self,widget):
+ _logger.debug('Reading a file into editor')
+ dialog = gtk.FileChooserDialog("Open..",
+ None,
+ gtk.FILE_CHOOSER_ACTION_OPEN,
+ (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OPEN, gtk.RESPONSE_OK))
+ dialog.set_default_response(gtk.RESPONSE_OK)
+ if self.last_filename == None:
+ self.last_filename = self.child_path
+ dialog.set_current_folder(os.path.dirname(self.last_filename))
+
+ filter = gtk.FileFilter()
+ filter.set_name("All files")
+ filter.add_pattern("*")
+ dialog.add_filter(filter)
+
+ filter = gtk.FileFilter()
+ filter.set_name("Python")
+ filter.add_pattern("*.py")
+ dialog.add_filter(filter)
+
+ filter = gtk.FileFilter()
+ filter.set_name("Activity")
+ filter.add_pattern("*.xo")
+ dialog.add_filter(filter)
+
+ response = dialog.run()
+ if response == gtk.RESPONSE_OK:
+ _logger.debug(dialog.get_filename(), 'selected')
+ fname = dialog.get_filename()
+ self.last_filename = fname
+ self.editor.load_object(fname,os.path.basename(fname))
+ elif response == gtk.RESPONSE_CANCEL:
+ _logger.debug( 'File chooseer closed, no files selected')
+ dialog.destroy()
+
+ def save_file_cb(self, button):
+ """
+ impliments the SaveAs function
+ """
+ chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_SAVE,
+ buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,
+ gtk.RESPONSE_OK))
+ file_path = self.editor.get_full_path()
+ _logger.debug('Saving file %s'%(file_path))
+ chooser.set_filename(file_path)
+ response = chooser.run()
+ new_fn = chooser.get_filename()
+ chooser.destroy()
+ if response == gtk.RESPONSE_CANCEL:
+ return
+ if response == gtk.RESPONSE_OK:
+ self.save_cb(None,new_fn)
+
+ def save_cb(self,button,new_fn=None):
+ if new_fn:
+ full_path = new_fn
+ else:
+ full_path = self.editor.get_full_path()
+ if os.path.basename(full_path).startswith('Unsaved_Document'): #force a choice to keep or change the name
+ #fd = open(full_path,'w')
+ #fd.close()
+ self.save_file_cb(None)
+ return
+ page = self.editor._get_page()
+ if new_fn:
+ page.fullPath = new_fn
+ page.save(skip_md5 = True)
+ else:
+ page.save()
+ self.editor.clear_changed_star()
+ page.save_hash()
+
+ def set_dirty(self, dirty):
+ self.dirty = dirty
+
+ def md5sum_buffer(self, buffer, hash = None):
+ if hash == None:
+ hash = hashlib.md5()
+ hash.update(buffer)
+ return hash.hexdigest()
+
+ def md5sum(self, filename, hash = None):
+ h = self._md5sum(filename,hash)
+ return h.hexdigest()
+
+ def _md5sum(self, filename, hash = None):
+ if hash == None:
+ hash = hashlib.md5()
+ try:
+ fd = None
+ fd = open(filename, 'rb')
+ while True:
+ block = fd.read(128)
+ if not block: break
+ hash.update(block)
+ finally:
+ if fd != None:
+ fd.close()
+ return hash
+
+ def md5sum_tree(self,root):
+ if not os.path.isdir(root):
+ return None
+ h = hashlib.md5()
+ for dirpath, dirnames, filenames in os.walk(root):
+ for filename in filenames:
+ abs_path = os.path.join(dirpath, filename)
+ h = self._md5sum(abs_path,h)
+ #print abs_path
+ return h.hexdigest()
+
+
+
+ ############## Following code services the Project page #####################
+
+ def _get_project_canvas(self):
+ #initialize the link between program and the glade XML file
+ self.wTree=gtk.glade.XML(os.path.join(self.sugar_bundle_path,"project.glade"))
+ self.contents = self.wTree.get_widget("contents")
+ self.contents.unparent()
+ return self.contents
+
+ def setup_project_page(self):
+ self.activity_treeview = self.wTree.get_widget('file_system')
+ self.activity_window = FileTree(self, self.activity_treeview,self.wTree)
+ self.activity_window.set_file_sys_root('/home/olpc/Activities')
+ self.examples_treeview = self.wTree.get_widget('examples')
+ self.examples_window = FileTree(self, self.examples_treeview,self.wTree)
+ self.examples_window.set_file_sys_root(os.path.join(self.sugar_bundle_path,'examples'))
+ self.journal_treeview = self.wTree.get_widget('journal')
+ self.journal_class = DataStoreTree(self,self.journal_treeview,self.wTree)
+ self.connect_object() #make connections to signals from buttons
+ self.activity_toggled_cb(None)
+ if self.child_path and self.child_path.endswith('.activity') and \
+ os.path.isdir(self.child_path):
+ self.setup_new_activity()
+ """
+ #get set to sense addition of a usb flash drive
+ self.volume_monitor = gio.volume_monitor_get()
+ self.volume_monitor.connect('mount-added',self.__mount_added_cb)
+ self.volume_monitor.connect('mount-removed',self.__mount_removed_cb)
+ mount_list = self.volume_monitor.get_mounts()
+ for m in mount_list:
+ s = m.get_root().get_path()
+ if s.startswith('/media'):_logger.debug('volume:%s',s)
+ """
+ def __mount_added_cb(self, vm, mount):
+ pass
+
+ def __mount_removed_cb(self, vm, mount):
+ pass
+
+ def display_current_project(self):
+ #try to colorize the playpen
+ pp = self.wTree.get_widget('playpen_event_box')
+ map = pp.get_colormap()
+ color = map.alloc_color(PROJECT_BG)
+ style = pp.get_style().copy()
+ style.bg[gtk.STATE_NORMAL] = color
+ pp.set_style(style)
+
+ self.manifest_treeview = self.wTree.get_widget('manifest')
+ map =self.manifest_treeview.get_colormap()
+ color = map.alloc_color(PROJECT_BASE)
+ style = self.manifest_treeview.get_style().copy()
+ style.bg[gtk.STATE_NORMAL] = color
+ color = map.alloc_color(PROJECT_BASE)
+ style.base[gtk.STATE_NORMAL] = color
+ self.manifest_treeview.set_style(style)
+ if self.manifest_class == None:
+ self.manifest_class = FileTree(self, self.manifest_treeview,self.wTree)
+ self.manifest_class.set_file_sys_root(self.child_path)
+
+ name = self.wTree.get_widget('name')
+ #map = name.get_colormap()
+ color = map.alloc_color(PROJECT_BASE)
+ style = name.get_style().copy()
+ style.base[gtk.STATE_NORMAL] = color
+ name.set_style(style)
+ name.set_text(self.activity_dict.get('name',''))
+
+ version = self.wTree.get_widget('version')
+ version.set_style(style)
+ version.set_text(self.activity_dict.get('version',''))
+
+ bundle = self.wTree.get_widget('bundle_id')
+ bundle.set_style(style)
+ bundle.set_text(self.activity_dict.get('bundle_id',''))
+
+ pyclass = self.wTree.get_widget('class')
+ pyclass.set_style(style)
+ pyclass.set_text(self.activity_dict.get('class',''))
+
+ pymodule = self.wTree.get_widget('module')
+ pymodule.set_style(style)
+ pymodule.set_text(self.activity_dict.get('module',''))
+ """
+ self.wTree.get_widget('home_save').set_text(self.activity_dict.get('home_save',''))
+ self.wTree.get_widget('host').set_text(self.debug_dict.get('host',''))
+ self.wTree.get_widget('port').set_text(str(self.debug_dict.get('port','')))
+ activity_size = os.system('du --max-depth=0')
+ self.wTree.get_widget('activity_size').set_text(str(activity_size))
+ self.wTree.get_widget('icon').set_text(self.activity_dict.get('icon','').split('/')[-1:][0])
+ """
+
+ def manifest_point_to(self,fullpath):
+ if self.child_path:
+ self.manifest_class.set_file_sys_root(self.child_path)
+ else:
+ self.manifest_class.set_file_sys_root(self.activity_playpen)
+ self.manifest_class.position_to(fullpath)
+
+ #first connect the glade xml file to the servicing call backs
+ def connect_object(self, wTree=None):
+ """if wTree:
+ self.wTree=wTree
+ if self.wTree:"""
+ mdict = {
+ 'name_changed_cb':self.name_changed_cb,
+ 'bundle_id_changed_cb':self.bundle_id_changed_cb,
+ 'class_changed_cb':self.class_changed_cb,
+ 'icon_changed_cb':self.icon_changed_cb,
+ 'version_changed_cb':self.version_changed_cb,
+ 'file_toggle_clicked_cb':self.activity_toggled_cb,
+ 'to_activities_clicked_cb':self.to_home_clicked_cb,
+ 'from_activities_clicked_cb':self.from_home_clicked_cb,
+ 'from_examples_clicked_cb':self.from_examples_clicked_cb,
+ 'help_clicked_cb':self.project_help_cb,
+ 'delete_file_clicked_cb':self.delete_file_cb,
+ 'clear_clicked_cb':self.clear_clicked_cb,
+ }
+ self.wTree.signal_autoconnect(mdict)
+ button = self.wTree.get_widget('file_toggle')
+ button.set_tooltip_text(_('Switch views between the "Installed" Activities directory and your "home" storage directory'))
+ button = self.wTree.get_widget('to_activities')
+ button.set_tooltip_text(_('Copy the files in the debug workplace to your "home" storage directory'))
+ button = self.wTree.get_widget('from_examples')
+ button.set_tooltip_text(_('Load and modify these example programs. See the help Tutorials'))
+
+ button = self.wTree.get_widget('delete_file')
+ map = button.get_colormap()
+ color = map.alloc_color(PROJECT_FG)
+ style = button.get_style().copy()
+ style.bg[gtk.STATE_NORMAL] = color
+ button.set_style(style)
+
+ button = self.wTree.get_widget('clear')
+ button.set_style(style)
+
+ button = self.wTree.get_widget('help')
+ button.set_style(style)
+
+ def project_help_cb(self):
+ self.help_selected()
+
+ def name_changed_cb(self, widget):
+ self.activity_dict['name'] = widget.get_text()
+
+ def bundle_id_changed_cb(self,widget):
+ self.activity_dict['bundle_id'] = widget.get_text()
+
+ def class_changed_cb(self, widget):
+ self.activity_dict['class'] = widget.get_text()
+
+ def icon_changed_cb(self, widget):
+ self.activity_dict['icon'] = widget.get_text()
+
+ def version_changed_cb(self, widget):
+ self.activity_dict['version'] = widget.get_text()
+
+ def name_changed_cb(self, widget):
+ self.activity_dict['name'] = widget.get_text()
+
+ def commit_changed_cb(self, widget):
+ self.activity_dict['commit_text'] = widget.get_text()
+
+ def volume_drop_changed_cb(self, widget):
+ self.activity_dict['name'] = widget.get_text()
+
+ def volume_save_cb(self, widget):
+ self.activity_dict['save'] = widget.get_text()
+
+ def activity_toggled_cb(self, widget):
+ _logger.debug('Entered activity_toggled_cb. Button: %r'%self.file_pane_is_activities)
+ but = self.wTree.get_widget('to_activities')
+ to_what = self.wTree.get_widget('file_toggle')
+ window_label = self.wTree.get_widget('file_system_label')
+ if self.file_pane_is_activities == True:
+ to_what.set_label('Installed_')
+ but.show()
+ #display_label = self.storage[:18]+' . . . '+self.storage[-24:]
+ display_label = 'PyDebug HOME storage:'
+ self.activity_window.set_file_sys_root(self.storage)
+ button = self.wTree.get_widget('from_activities')
+ button.set_tooltip_text(_('Copy the selected directory or file from your "home" storage to the debug workplace'))
+ window_label.set_text(display_label)
+ else:
+ to_what.set_label('home')
+ but.hide()
+ self.activity_window.set_file_sys_root('/home/olpc/Activities')
+ button = self.wTree.get_widget('from_activities')
+ button.set_tooltip_text(_('Copy the selected Activity or file to the debug workplace'))
+ window_label.set_text('INSTALLED ACTIVITIES:')
+ self.file_pane_is_activities = not self.file_pane_is_activities
+
+ def to_home_clicked_cb(self,widget):
+ _logger.debug('Entered to_home_clicked_cb')
+ self._to_home_dest = os.path.join(self.storage,self.activity_dict['name']+'.activity')
+ if False: #os.path.isdir(self._to_home_dest):
+ target_md5sum = self.md5sum_tree(self._to_home_dest)
+ if target_md5sum != self.debug_dict.get('tree_md5',''):
+ self.confirmation_alert(_('OK to delete/overwrite %s?'%self._to_home_dest),
+ _('This destination has been changed by another application'),
+ self._to_home_cb)
+ return
+ self._to_home_cb( None, gtk.RESPONSE_OK)
+
+ def _to_home_cb(self, alert, response_id):
+ if alert != None: self.remove_alert(alert)
+ if response_id is gtk.RESPONSE_OK:
+ cmd = ['rsync','-av',self.child_path + '/',self._to_home_dest]
+ _logger.debug('do to_home_cb with cmd:%s'%cmd)
+ p1 = Popen(cmd,stdout=PIPE)
+ output = p1.communicate()
+ if p1.returncode != 0:
+ self.alert('rsync command returned non zero\n'+output[0]+ 'COPY FAILURE')
+ return
+ #redraw the treeview
+ self.activity_window.set_file_sys_root(self.storage)
+
+ def from_home_clicked_cb(self,widget):
+ _logger.debug('Entered from_home_clicked_cb')
+ selection=self.activity_treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.alert(_('Must select File or Directory item to Load'))
+ return
+ fullpath = model.get(iter,4)[0]
+ if os.path.isdir(fullpath):
+ if not fullpath.endswith('.activity'):
+ self.alert(_('Use this button for Activities or Files'),
+ _('ERROR: This folder name does not end with ".activity"'))
+ return
+ self.load_activity_to_playpen(fullpath)
+ else:
+ #selected is a file, just copy it into the current project
+ basename = os.path.basename(fullpath)
+ if os.path.isfile(os.path.join(self.child_path,basename)):
+ #change name if necessary to prevent collision
+ basename = self.non_conflicting(self.child_path,basename)
+ shutil.copy(fullpath,os.path.join(self.child_path,basename))
+ self.manifest_point_to(os.path.join(self.child_path,basename))
+
+ def non_conflicting(self,root,basename):
+ """
+ create a non-conflicting filename by adding '-<number>' to a filename before extension
+ """
+ ext = ''
+ basename = basename.split('.')
+ word = basename[0]
+ if len(basename) > 1:
+ ext = basename[1]
+ adder = ''
+ index = 0
+ while os.path.isfile(os.path.join(root,word+adder+'.'+ext)):
+ index +=1
+ adder = '-%s'%index
+ return os.path.join(root,word+adder+'.'+ext)
+
+ def from_examples_clicked_cb(self,widget):
+ _logger.debug('Entered from_examples_clicked_cb')
+ selection=self.examples_treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.alert(_('Must select File or Directory item to Load'))
+ return
+ fullpath = model.get(iter,4)[0]
+ if fullpath.endswith('.activity'):
+ self.load_activity_to_playpen(fullpath)
+ return
+ self._load_to_playpen_source = fullpath
+ try:
+ self._bundler = ActivityBundle(fullpath)
+ except:
+ self.alert('Error: Malformed Activity Bundle')
+ return
+
+ self._new_child_path = os.path.join(self.activity_playpen,self._bundler._zip_root_dir)
+ #check to see if current activity in playpen needs to be saved, and load new activity if save is ok
+ self._load_playpen(fullpath, iszip=True)
+
+ def filetree_activated(self):
+ _logger.debug('entered pydebug filetree_activated')
+
+ def read_activity_info(self, path):
+ """
+ Parses the ./activity/activity.info file
+
+ filen = os.path.join(self.child_path,'activity','activity.info')
+ try:
+ fd = open(filen,'r')
+ except:
+ _logger.debug('failed to open %s'%filen)
+ return
+ for line in fd.readlines():
+ if line.lstrip() == '': continue
+ _logger.debug('activity line %s'%line)
+ tokens = line.split('=')
+
+ if len(tokens) > 1:
+ keyword = tokens[0].lower().rstrip()
+ rside = tokens[1].split()
+ if keyword == 'class':
+ if '.' in rside[0]:
+ self.activity_dict['class'] = rside[0].split('.')[1]
+ self.activity_dict['module'] = rside[0].split('.')[0]
+ elif keyword == 'exec':
+ if rside[0] == 'sugar-activity' and '.' in rside[1]:
+ self.activity_dict['class'] = rside[1].split('.')[1]
+ self.activity_dict['module'] = rside[1].split('.')[0]
+ else:
+ self.activity_dict['module'] = rside[0]
+ elif keyword == 'bundle_id' or keyword == 'service_name':
+ self.activity_dict['bundle_id'] = rside[0]
+ elif keyword == 'activity_version':
+ self.activity_dict['version'] = rside[0]
+ elif keyword == 'name':
+ self.activity_dict['name'] = rside[0]
+ elif keyword == 'icon':
+ self.activity_dict['icon'] = rside[0]
+ fd.close()
+
+ debugstr = ''
+ for key in self.activity_dict.keys():
+ debugstr += key + ':'+str(self.activity_dict[key]) + ', '
+ _logger.debug ('In read_activity: activity dictionary==> %s'%debugstr)
+ """
+ try:
+ bundle = ActivityBundle(path)
+ except:
+ #msg = _('%s not recognized by ActivityBundle parser. Does activity/activity.info exist?'%os.path.basename(path))
+ #self.alert(msg)
+ self.init_activity_dict()
+ return #maybe should issue an alert here
+ self.activity_dict['version'] = str(bundle.get_activity_version())
+ self.activity_dict['name'] = bundle.get_name()
+ self.activity_dict['bundle_id'] = bundle.get_bundle_id()
+ self.activity_dict['command'] = bundle.get_command()
+ cmd_args = activityfactory.get_command(bundle)
+ mod_class = cmd_args[1]
+ if '.' in mod_class:
+ self.activity_dict['class'] = mod_class.split('.')[1]
+ self.activity_dict['module'] = mod_class.split('.')[0]
+ self.activity_dict['icon'] = bundle.get_icon()
+
+ def init_activity_dict(self):
+ self.activity_dict['version'] = '1'
+ self.activity_dict['name'] = 'untitled'
+ self.activity_dict['bundle_id'] = ''
+ self.activity_dict['command'] = ''
+ self.activity_dict['class'] = ''
+ self.activity_dict['module'] = ''
+ self.activity_dict['icon'] = ''
+
+ def write_activity_info(self):
+ #write the activity.info file
+ _logger.debug('entered write_actiity_info')
+ if self.child_path == None: return
+ filen = os.path.join(self.child_path,'activity','activity.info')
+ try:
+ with open(filen,'r') as fd:
+ #and also write to a new file
+ filewr = os.path.join(self.child_path,'activity','activity.new')
+ #try:
+ with open(filewr,'w') as fdw:
+ #write the required lines
+ _logger.debug('writing activity info to %s'%filewr)
+ fdw.write('[Activity]\n')
+ fdw.write('name = %s\n'%self.activity_dict.get('name'))
+ fdw.write('bundle_id = %s\n'%self.activity_dict.get('bundle_id'))
+ fdw.write('activity_version = %s\n'%self.activity_dict.get('version'))
+ icon = self.activity_dict.get('icon')[len(self.child_path)+10:-4]
+ fdw.write('icon = %s\n'%icon)
+ if self.activity_dict.get('class','') == '':
+ fdw.write('exec = %s\n'%self.activity_dict.get('module'))
+ else:
+ fdw.write('class = %s.%s\n'%(self.activity_dict.get('module'),
+ self.activity_dict.get('class')))
+ #pass the rest of the input to the output
+ passup = ('[activity]','exec','activity_version','name','bundle_id',
+ 'service_name','icon','class')
+ for line in fd.readlines():
+ tokens = line.split('=')
+ keyword = tokens[0].lower().rstrip()
+ if keyword in passup: continue
+ fdw.write(line)
+ return True
+ except:
+ return False
+ """
+ except EnvironmentError:
+ _logger.debug('failed to open %s for writing. msg:%s'%(filewr,EnvironmentError[1]))
+
+ except EnvironmentError:
+ _logger.debug('failed to open %s msg:%s'%(filen,EnvironmentError[1]))
+ """
+
+ def delete_file_cb(self,widget):
+ selection=self.manifest_treeview.get_selection()
+ (model,iter)=selection.get_selected()
+ if iter == None:
+ self.alert(_('Must select a File or Folder to delete'))
+ return
+ fullpath = model.get(iter,4)[0]
+ _logger.debug(' delete_file_clicked_cb. File: %s'%(fullpath))
+ self.delete_file_storage = fullpath
+ if os.path.isdir(fullpath):
+ self.confirmation_alert(_('Would you like to continue deleting %s?'%os.path.basename(fullpath)),
+ _('CAUTION: You are about to DELETE a FOLDER!!'),self.do_delete_folder)
+ return
+ self.confirmation_alert(_('Would you like to continue deleting %s?'%os.path.basename(fullpath)),
+ _('ABOUT TO DELETE A FILE!!'),self.do_delete)
+
+ def do_delete(self, alert, response):
+ _logger.debug('doing delete of: %s'%self.delete_file_storage)
+ self.manifest_point_to(self.delete_file_storage)
+ os.unlink(self.delete_file_storage)
+ self.manifest_class.set_file_sys_root(self.child_path)
+ self.manifest_class.position_recent()
+
+ def do_delete_folder(self, alert, response):
+ _logger.debug('doing delete of: %s'%self.delete_file_storage)
+ self.manifest_point_to(self.delete_file_storage)
+ shutil.rmtree(self.delete_file_storage)
+ self.manifest_class.set_file_sys_root(self.child_path)
+ self.manifest_class.position_recent()
+
+ def clear_clicked_cb(self, button):
+ self.editor.remove_all()
+ self.init_activity_dict()
+ self.child_path = None
+ self.manifest_class.set_file_sys_root(self.child_path)
+ self.display_current_project()
+
+ ################ Help routines
+ def help_selected(self):
+ """
+ if help is not created in a gtk.mainwindow then create it
+ else just switch to that viewport
+ """
+ if not self.help_x11:
+ #self.window_instance = self.window.window
+ self.help_x11 = self.help.realize_help()
+ #self.x11_window = self.get_x11()os.geteuid()
+ else:
+ self.help.activate_help()
+ #self.help.reshow()
+ #self.help.toolbox.set_current_page(self.panes['HELP']
+ """
+ def get_x11(self):
+ home_model = shell.get_model()
+ activity = home_model.get_active_activity()
+ if activity and activity.get_window():
+
+ return activity.get_window().activate(1)
+ else:
+ return None
+ """
+ ################ save config state from one invocation to another -- not activity state
+ def get_config(self):
+ try:
+ fd = open(os.path.join(self.debugger_home,'pickl'),'rb')
+ local = pickle.load(fd)
+ self.debug_dict = local.copy()
+ _logger.debug('unpickled successfully')
+ """
+ object_id = self.debug_dict.get('jobject_id','')
+ if object_id != '':
+ self._jobject = datastore.get(object_id)
+ else:
+ self._jobject = None
+ """
+ except:
+ try:
+ fd = open(os.path.join(self.debugger_home,'pickl'),'wb')
+ self.debug_dict['host'] = 'localhost'
+ self.debug_dict['port'] = 18812
+ self.debug_dict['autosave'] = True
+ self.debug_dict['child_path'] = ''
+ local = self.debug_dict.copy()
+ pickle.dump(local,fd,pickle.HIGHEST_PROTOCOL)
+ except IOError:
+ _logger.debug('get_config -- Error writing pickle file %s'
+ %os.path.join(self.debugger_home,'pickl'))
+ finally:
+ fd.close()
+ object_id = self.debug_dict.get('jobject_id','')
+ if object_id == '':
+ jobject = self.get_new_dsobject()
+ self._jobject = jobject
+ self.debug_dict['jobject_id'] = str(self._jobject.object_id)
+ _logger.debug('in get_config created jobject id:%s'%self.debug_dict['jobject_id'])
+ else:
+ pass
+ #self._jobject = datastore.get(object_id)
+ self.child_path = self.debug_dict.get('child_path','')
+ if self.child_path == '' or not os.path.isdir(self.child_path):
+ self.child_path = None
+
+ debugstr = ''
+ for key in self.debug_dict.keys():
+ debugstr += key + ':'+str(self.debug_dict[key]) + ', '
+ _logger.debug ('In get_config: debug dictionary==> %s'%debugstr)
+
+ def get_new_dsobject(self):
+ jobject = datastore.create()
+ jobject.metadata['title'] = 'PyDebug'
+ jobject.metadata['activity'] = 'org.laptop.PyDebug'
+ jobject.metadata['keep'] = '1'
+ jobject.metadata['preview'] = ''
+ datastore.write(jobject)
+ return jobject
+
+ def check_child_md5(self):
+ if self.child_path and self.debug_dict.get('tree_md5',''):
+ if self.debug_dict.get('tree_md5','') == self.md5sum_tree(self.child_path):
+ self.setup_new_activity()
+ #the tree is valid so take up where we left off
+ else:
+ self.confirmation_alert(_('Continue even though stored checksum does not match current checksum'),
+ _('CAUTION: The program in the playpen may have been changed.'),
+ self.startup_continue)
+
+ def startup_continue(self,alert,response):
+ self.setup_new_activity()
+
+ def put_config(self):
+ if self.child_path:
+ self.debug_dict['tree_md5'] = self.md5sum_tree(self.child_path)
+ self.debug_dict['child_path'] = self.child_path
+ try:
+ fd = open(os.path.join(self.debugger_home,'pickl'),'wb')
+ local = self.debug_dict.copy()
+ pickle.dump(local,fd,pickle.HIGHEST_PROTOCOL)
+ except IOError:
+ _logger.debug('put_config routine Error writing pickle file %s'
+ %os.path.join(self.debugger_home,'pickl'))
+ return
+ finally:
+ fd.close()
+ debugstr = ''
+ return
+ for key in self.debug_dict.keys():
+ debugstr += key + ':'+str(self.debug_dict[key]) + ', '
+ _logger.debug ('In put_config: debug dictionary==> %s'%debugstr)
+