1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
|
#!/usr/bin/env python
# encoding: utf-8
"""
sugarbot-launcher.py
This file is part of sugarbot.
sugarbot 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 3 of the License, or
(at your option) any later version.
sugarbot 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 sugarbot. If not, see <http://www.gnu.org/licenses/>.
"""
import logging
import os
import signal
import sys
import socket
from subprocess import Popen
from time import time,sleep
from xmlrpclib import ServerProxy
# Set the Sugarbot path env var if it has not already been set
if not os.environ.has_key('SUGARBOT_PATH'):
os.environ['SUGARBOT_PATH']=os.getcwd()
# Add the sugarbot path to the include-path
sys.path.append(os.environ['SUGARBOT_PATH'])
# Import sugar-specific stuff
from sbrpcserver import proxyString, rebuildMarshalledObject, sugarbotSession
try:
from sbconfig import clientName
except ImportError:
from sbconfig_sample import clientName
class SugarProcessHandler():
"""
Handles launching and monitoring of the Sugar process.
"""
def __init__(self):
# Set the environment variable to emulate, and the executed scripts.
os.environ['SUGARBOT_EMULATOR']='1'
# Get the connection to the XML-RPC server
self.xml = self.connectToXMLRPC()
logging.info("Connected to XML-RPC server %s" % proxyString())
# Get our ID and reset the state
self.ID = self.getSugarbotClientID()
self.xml.resetClientState(self.ID)
logging.info("Using session ID %s" % self.ID)
def getSugarbotClientID(self):
"""
Retrieves whatever ID we should be using. This is either set by the
environment variables, the configuration file, or generated by the
server.
"""
# If we have not specified a sugarbot ID, specify one now
if not os.environ.has_key('SUGARBOT_ID'):
if not clientName:
os.environ['SUGARBOT_ID']=str(xml.generateSessionID())
else:
os.environ['SUGARBOT_ID']=clientName
return os.environ['SUGARBOT_ID']
def connectToXMLRPC(self):
"""
Connects to the ML-RPC server, tests connectivity.
"""
xml = ServerProxy(proxyString())
try:
xml.testConnectivity()
except:
logging.fatal('Could not connect to the XML-RPC server')
sys.exit(1)
return xml
def launchSugar(self):
"""
Launches the sugar-emulator process and waits for it to finish.
"""
# Launch the process
self.pid = Popen('sugar-emulator')
self.waitForSugarbotExecution()
def waitForSugarbotExecution(self):
"""
Waits a certain amount of time for Sugar to quit.
If Sugar does not die in the alloted time, it is killed.
"""
# Wait five minutes for the tests to execute? Why not.
start = time()
wait = 60*5
done = start + wait
# We've waited long enough. Kill it!
while self.pid.poll() is None and done > time():
sleep(0.1)
if self.pid.poll() is None:
logging.fatal("Had to send SIGTERM to Sugar process")
os.kill(self.pid.pid, signal.SIGTERM)
def getReturnValue(self):
"""
Determines whether all of the tests succeeded, or there was a failure.
0 = All tests succeeded
1 = At least one failure
"""
# Get the completion status...
sessionDict = self.xml.completionStatus(self.ID)
if sessionDict is None:
logging.error("Could not get completion status from XMLRPC server")
return -1
session = sugarbotSession()
rebuildMarshalledObject(session, sessionDict)
# Get whatever the return value should be.
retval = session.getSuccessValue()
# Print out the completion statuses all pretty-like
status = ""
logging.info("Script completion statuses:")
for script in session.responses:
logging.info("\t%s: %s" % (session.responses[script], script))
# if session.failureText.has_key(script) and \
# not session.responses[script]:
if not session.responses[script]:
logging.info("================ [%s] ================", script)
for line in session.failureText[script].split('\n'):
if len(line) > 0:
logging.info(line)
logging.info("================ [%s] ================", script)
# Check the number of scripts to make sure they all executed
numScripts = self.xml.numberOfScripts()
if( numScripts > len(session.responses) ):
retval = False
logging.warning("Only executed %i/%i scripts" % \
(numScripts,len(session.responses)) )
return retval
def main():
s = SugarProcessHandler()
s.launchSugar()
retval = s.getReturnValue()
logging.info("Returning %s" % retval)
return retval
if __name__ == "__main__":
main()
else:
import pygtk
pygtk.require('2.0')
import gtk
import gobject
import time
from view.Shell import Shell
from model.shellmodel import ShellModel
from shellservice import ShellService
from view.frame.activitiestray import ActivitiesTray
from view.frame.activitybutton import ActivityButton
class SugarbotLauncher:
"""
Autmates the launching and re-launching of Sugarbot from the main Sugar
GUI. This automation is handled by simulating a click on the Sugarbot
activity icon in the Sugar Pane.
"""
activityName = "sugarbot"
def __init__(self, shell, shellModel):
gtk.gdk.event_handler_set(self.eventHandler)
self.model = shellModel
self.numberOfScripts = 0
self.shell = shell
self.sugarbotIsRunning = False
self.timesLaunched = 0
self.xml = ServerProxy(proxyString())
home = self.model.get_home()
home.connect('activity-started', self._activity_started_cb)
home.connect('activity-removed', self._activity_removed_cb)
home.connect('active-activity-changed', self._activity_active_cb)
home.connect('pending-activity-changed', self._activity_pending_cb)
def isSugarbotActivity(self,activity):
"""
Checks to see if an 'Activity' object is the sugarbot activity.
"""
if activity._activity_info.name == self.activityName:
if self.numberOfScripts <= 0:
self.doSetup(activity)
return True
return False
def doSetup(self, activity):
"""
Prepares for launching the activity, given its information.
"""
path = activity._activity_info.path
sys.path.append(path)
try:
self.numberOfScripts = self.xml.numberOfScripts()
except:
logging.fatal("Could not connect to XMLRPC Server")
sys.exit(-1)
def _activity_started_cb(self, model, activity):
if self.isSugarbotActivity(activity):
self.sugarbotIsRunning = True
self.timesLaunched += 1
def _activity_removed_cb(self, model, activity):
if self.isSugarbotActivity(activity):
self.sugarbotIsRunning = False
if self.xml.getKillFlag() and \
1 <= self.numberOfScripts <= self.timesLaunched:
logging.info("Sugarbot execution completed successfully")
self.killSugar()
def _activity_active_cb(self, model, activity):
pass
def _activity_pending_cb(self, model, activity):
pass
def killSugar(self):
"""
Sends SIGTERM to the Sugar process.
"""
try:
if os.environ.has_key('SUGAR_EMULATOR_PID'):
pid = int(os.environ['SUGAR_EMULATOR_PID'])
os.kill(pid, signal.SIGTERM)
except:
raise
def tryToLaunchSugarbotActivity(self):
"""
Attempts to launch sugarbot.
"""
if self.sugarbotIsRunning or not self.xml.getRestartFlag():
# time.sleep(0.1)
return
frame = self.shell.get_frame()
frameBottomPanel = frame._bottom_panel
bottomPanelChildren = frameBottomPanel._bg.get_children()
tray = [k for k in bottomPanelChildren if isinstance(k,ActivitiesTray)]
if tray:
trayIcons = tray[0]._tray.get_children()
else:
return
activities = [k for k in trayIcons if isinstance(k, ActivityButton)]
sbList = [k for k in activities if \
k._activity_info.name == self.activityName]
if len(sbList) > 0:
sbList[0].emit('clicked')
self.sugarbotIsRunning = True
def eventHandler(self, event):
"""
Intercepts GTK calls, to attempt to launch sugarbot.
Attempts to launch sugarbot at every gdk.Event emitted.
"""
if event is not None:
gtk.main_do_event(event)
self.tryToLaunchSugarbotActivity()
|