Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/rpms/sugar-toolkit/0028-Report-to-the-shell-on-errors.patch
blob: c72ec610601f04801e5f37d45f6a78c01a20a429 (plain)
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
From 2c5098ff2bc6918a867b5bd736784fefd9ca774b Mon Sep 17 00:00:00 2001
From: Aleksey Lim <alsroot@member.fsf.org>
Date: Tue, 18 Jan 2011 08:00:27 +0000
Subject: [PATCH 28/33] Report to the shell on errors
Organization: Sugar Labs Foundation

m 72f0694200feccd88646e21aadb1c5bde36e7ca3 Mon Sep 17 00:00:00 2001
From: Aleksey Lim <alsroot@member.fsf.org>
Date: Wed, 19 Jan 2011 18:47:58 +0000
Subject: [PATCH sugar-toolkit] Report to the shell on errors
---
 src/sugar/Makefile.am                 |    1 +
 src/sugar/activity/activityfactory.py |   10 +++-
 src/sugar/activity/main.py            |    4 +-
 src/sugar/feedback.py                 |  103 +++++++++++++++++++++++++++++++++
 4 files changed, 115 insertions(+), 3 deletions(-)
 create mode 100644 src/sugar/feedback.py

diff --git a/src/sugar/Makefile.am b/src/sugar/Makefile.am
index c1ff933..eb4590e 100644
--- a/src/sugar/Makefile.am
+++ b/src/sugar/Makefile.am
@@ -2,6 +2,7 @@ SUBDIRS = activity bundle graphics presence datastore
 
 sugardir = $(pythondir)/sugar
 sugar_PYTHON =		\
+	feedback.py \
 	env.py		\
         network.py	\
 	profile.py	\
diff --git a/src/sugar/activity/activityfactory.py b/src/sugar/activity/activityfactory.py
index a206d15..0da997e 100644
--- a/src/sugar/activity/activityfactory.py
+++ b/src/sugar/activity/activityfactory.py
@@ -25,6 +25,7 @@ the moment there is no reason to stabilize this API.
 import logging
 import uuid
 
+import cjson
 import dbus
 import gobject
 
@@ -260,7 +261,7 @@ class ActivityCreationHandler(gobject.GObject):
 
         gobject.child_watch_add(child.pid,
                                 _child_watch_cb,
-                                (environment_dir, log_file,
+                                (environment_dir, log_file, log_path,
                                     self._handle.activity_id))
 
     def _no_reply_handler(self, *args):
@@ -324,7 +325,7 @@ def create_with_object_id(bundle, object_id):
 def _child_watch_cb(pid, condition, user_data):
     # FIXME we use standalone method here instead of ActivityCreationHandler's
     # member to have workaround code, see #1123
-    environment_dir, log_file, activity_id = user_data
+    environment_dir, log_file, log_path, activity_id = user_data
     if environment_dir is not None:
         subprocess.call(['/bin/rm', '-rf', environment_dir])
 
@@ -367,6 +368,11 @@ def _child_watch_cb(pid, condition, user_data):
         def error_handler_cb(error):
             logging.error('Cannot send NotifyLaunchFailure to the shell')
 
+        report = cjson.encode({'failed_exit': 1})
+        shell.Feedback(activity_id, report, log_path,
+                reply_handler=reply_handler_cb,
+                error_handler=error_handler_cb)
+
         # TODO send launching failure but activity could already show
         # main window, see http://bugs.sugarlabs.org/ticket/1447#comment:19
         shell.NotifyLaunchFailure(activity_id,
diff --git a/src/sugar/activity/main.py b/src/sugar/activity/main.py
index d2a9302..d513085 100644
--- a/src/sugar/activity/main.py
+++ b/src/sugar/activity/main.py
@@ -30,7 +30,7 @@ from sugar.activity import activityhandle
 from sugar.activity import i18n
 from sugar.bundle.activitybundle import ActivityBundle
 from sugar.graphics import style
-from sugar import logger
+from sugar import logger, feedback
 
 
 def create_activity_instance(constructor, handle):
@@ -114,6 +114,8 @@ def main():
     gettext.bindtextdomain('sugar-toolkit', sugar.locale_path)
     gettext.textdomain(bundle.get_bundle_id())
 
+    feedback.start(options.activity_id)
+
     splitted_module = args[0].rsplit('.', 1)
     module_name = splitted_module[0]
     class_name = splitted_module[1]
diff --git a/src/sugar/feedback.py b/src/sugar/feedback.py
new file mode 100644
index 0000000..56dacab
--- /dev/null
+++ b/src/sugar/feedback.py
@@ -0,0 +1,103 @@
+# Copyright (C) 2011, Aleksey Lim
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+import os
+import sys
+import atexit
+import logging
+
+import dbus
+import cjson
+
+
+_SHELL_SERVICE = "org.laptop.Shell"
+_SHELL_PATH = "/org/laptop/Shell"
+_SHELL_IFACE = "org.laptop.Shell"
+
+_report = {}
+_need_log = False
+_log_formatter = None
+
+
+def start(activity_id, log_path=None):
+    if log_path is None:
+        # TODO more portable solution
+        stdout_file = os.readlink('/proc/self/fd/%s' % sys.stdout.fileno())
+        if os.path.isfile(stdout_file):
+            log_path = stdout_file
+        else:
+            log_path = ''
+
+    atexit.register(_send, activity_id, log_path)
+
+
+def trigger(key, need_log=False):
+    global _need_log
+
+    if key not in _report:
+        _report[key] = 0
+    _report[key] += 1
+    _need_log = _need_log or need_log
+
+    logging.debug('Feedback[%s] == %s', key, _report[key])
+
+
+def flush():
+    global _report
+    global _need_log
+
+    report = _report
+    need_log = _need_log
+    _report = {}
+    _need_log = False
+
+    return report, need_log
+
+
+def _send(activity_id, log_path):
+    if not _report:
+        return
+
+    report, need_log = flush()
+
+    bus = dbus.SessionBus()
+    bus_object = bus.get_object(_SHELL_SERVICE, _SHELL_PATH)
+    shell = dbus.Interface(bus_object, _SHELL_IFACE)
+    shell.Feedback(activity_id, cjson.encode(report),
+            log_path if need_log else '')
+
+
+def _excepthook(exctype, value, tb):
+    global _log_formatter
+
+    if _log_formatter is None:
+        try:
+            # Attempt to provide verbose IPython tracebacks.
+            # Importing IPython is slow, so we import it lazily.
+            from IPython.ultraTB import AutoFormattedTB
+            formatter = AutoFormattedTB(mode='Verbose', color_scheme='NoColor')
+            _log_formatter = formatter.text
+        except ImportError:
+            import traceback
+            _log_formatter = \
+                    lambda * args: ''.join(traceback.format_exception(*args))
+
+    message = _log_formatter(exctype, value, tb)
+    logging.error(message)
+
+    trigger('unhandled_exception', need_log=True)
+
+
+sys.excepthook = _excepthook
-- 
1.7.4.4