36
#FIXME: would be nice if we ran w/o GConf, do a try...except block around
37
# the import and then set have_gconf to false
42
41
import jhbuild.moduleset
43
42
from jhbuild.modtypes import MetaModule
44
43
from jhbuild.errors import CommandError
46
def get_glade_filename():
47
return os.path.join(os.path.dirname(__file__), 'jhbuild.glade')
50
def __init__(self, config, args):
44
from jhbuild.utils import notify
46
from terminal import t_bold, t_reset
49
class ExitRequestedException(Exception):
53
class AppWindow(gtk.Window, buildscript.BuildScript):
54
default_module_iter = None
57
error_resolution = None
58
preference_dialog = None
60
def __init__(self, config, module_list=None):
61
self.orig_modulelist = module_list
62
buildscript.BuildScript.__init__(self, config)
51
63
self.config = config
54
glade_filename = get_glade_filename()
56
# Fetch widgets out of the Glade
57
self.glade = gtk.glade.XML(glade_filename)
58
self.window = self.glade.get_widget("ConfigWindow")
59
self.meta_modules_list = self.glade.get_widget("ConfigMetaModules")
60
self.start_module_menu = self.glade.get_widget("ConfigStartModule")
61
self.run_autogen_checkbox = self.glade.get_widget("ConfigRunAutogen")
62
self.cvs_update_checkbox = self.glade.get_widget("ConfigCVSUpdate")
63
self.no_build_checkbox = self.glade.get_widget("ConfigNoBuild")
64
self.start_build_button = self.glade.get_widget("ConfigBuildButton")
65
self.cancel_button = self.glade.get_widget("ConfigCancelButton")
67
# Get settings for the checkboxes, etc
68
self._get_default_settings()
70
# Hook up the buttons / checkboxes
71
self.start_build_button.connect('clicked', lambda button: gtk.main_quit())
72
self.cancel_button.connect('clicked', lambda button: sys.exit(-1))
73
self.run_autogen_checkbox.connect('toggled', self._autogen_checkbox_toggled)
74
self.cvs_update_checkbox.connect('toggled', self._cvs_update_checkbox_toggled)
75
self.no_build_checkbox.connect('toggled', self._no_build_checkbox_toggled)
76
#self.start_module_menu.connect('clicked', self._start_module_menu_clicked)
78
# Get the list of meta modules
64
gtk.Window.__init__(self)
65
self.set_resizable(False)
66
theme = gtk.icon_theme_get_default()
67
gtk.window_set_default_icon_list(
68
theme.load_icon('applications-development', 16, ()),
69
theme.load_icon('applications-development', 24, ()),
70
theme.load_icon('applications-development', 32, ()),
71
theme.load_icon('applications-development', 48, ()),
72
theme.load_icon('applications-development', 64, ()),
73
theme.load_icon('applications-development', 128, ())
75
self.set_title('JHBuild')
79
77
self.module_set = jhbuild.moduleset.load(config)
79
self.create_modules_list_model()
81
self.notify = notify.Notify(config)
83
if self.default_module_iter:
84
self.module_combo.set_active_iter(self.default_module_iter)
86
self.connect('delete-event', self.on_delete_event)
88
def create_modules_list_model(self):
89
# name, separator, startat
90
self.modules_list_model = gtk.ListStore(str, bool, str)
80
91
full_module_list = self.module_set.get_full_module_list()
81
self.meta_modules = []
82
self.name_to_meta_module = {}
83
for possible_meta_module in full_module_list:
84
if isinstance(possible_meta_module, MetaModule):
85
print "Found meta module %s" % possible_meta_module.name
86
self.meta_modules.append(possible_meta_module)
87
self.name_to_meta_module[possible_meta_module.name] = possible_meta_module
89
self._create_meta_modules_list_view(self.meta_modules)
91
self._build_start_module_menu()
94
self.window.show_all()
97
self._set_default_settings()
98
return (self.module_list, self.start_at_module, self.run_autogen, self.cvs_update,
101
def _get_default_settings(self):
103
client = gconf.client_get_default()
104
self.run_autogen = client.get_bool("/apps/jhbuild/always_run_autogen")
105
self.cvs_update = client.get_bool("/apps/jhbuild/update_from_cvs")
106
self.no_build = client.get_bool("/apps/jhbuild/no_build")
107
self.selected_modules = client.get_list("/apps/jhbuild/modules_to_build", gconf.VALUE_STRING)
108
self.start_at_module = client.get_string("/apps/jhbuild/start_at_module")
110
self.run_autogen = False
111
self.cvs_update = True
112
self.no_build = False
114
self.run_autogen_checkbox.set_active(self.run_autogen)
115
self.cvs_update_checkbox.set_active(self.cvs_update)
116
self.no_build_checkbox.set_active(self.no_build)
118
def _set_default_settings(self):
120
client = gconf.client_get_default()
121
client.set_bool("/apps/jhbuild/always_run_autogen", self.run_autogen)
122
client.set_bool("/apps/jhbuild/update_from_cvs", self.cvs_update)
123
client.set_bool("/apps/jhbuild/no_build", self.no_build)
124
client.set_list("/apps/jhbuild/modules_to_build", gconf.VALUE_STRING, self.selected_modules)
125
if self.start_at_module:
126
client.set_string("/apps/jhbuild/start_at_module", self.start_at_module)
128
client.set_string("/apps/jhbuild/start_at_module", "")
130
print ("Gconf setting for update from CVS is %d" % self.cvs_update)
133
def _meta_module_toggled(self, cell, path, model):
134
iter = model.get_iter((int(path),))
135
build = model.get_value(iter, 0)
137
model.set(iter, 0, build)
138
self.selected_modules = self._get_selected_meta_modules()
139
self._build_start_module_menu()
141
def _create_meta_modules_list_view(self, meta_modules):
142
self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING)
143
self.meta_modules_list.set_model(self.model)
145
for module in meta_modules:
146
iter = self.model.append()
147
if self.selected_modules:
148
selected = (module.name in self.selected_modules)
151
self.model.set(iter, 0, selected, 1, module.name)
153
renderer = gtk.CellRendererToggle()
154
renderer.connect('toggled', self._meta_module_toggled, self.model)
155
column = gtk.TreeViewColumn('Build', renderer, active=0)
156
column.set_clickable(True)
157
self.meta_modules_list.append_column(column)
159
column = gtk.TreeViewColumn('Module Group', gtk.CellRendererText(), text=1)
160
self.meta_modules_list.append_column(column)
162
def _get_selected_meta_modules(self):
164
iter = self.model.get_iter_first()
167
build = self.model.get_value(iter, 0)
169
name = self.model.get_value(iter, 1)
170
module = self.name_to_meta_module[name]
172
modules.append(module.name)
173
iter = self.model.iter_next(iter)
178
def _build_start_module_menu(self):
179
if not self.selected_modules:
182
self.module_list = self.module_set.get_module_list(self.selected_modules, self.config.skip)
185
menu.connect('selection-done', self._start_module_menu_clicked)
187
selected_item_number = None
189
for module in self.module_list:
190
menu_item = gtk.MenuItem(module.name)
191
menu.append(menu_item)
192
if module.name == self.start_at_module:
193
selected_item_number = i
196
self.start_module_menu.set_menu (menu)
198
if selected_item_number:
199
self.start_module_menu.set_history(selected_item_number)
202
self.start_at_module = self.module_list[0].name
204
self.start_at_module = None
208
def _start_module_menu_clicked(self, option_menu):
209
number = self.start_module_menu.get_history()
211
item = self.module_list[number]
212
self.start_at_module = item.name
214
self.start_at_module = None
216
def _autogen_checkbox_toggled(self, checkbox):
217
self.run_autogen = not self.run_autogen
219
def _cvs_update_checkbox_toggled(self, checkbox):
220
self.cvs_update = not self.cvs_update
222
def _no_build_checkbox_toggled(self, checkbox):
223
self.no_build = not self.no_build
225
def optionmenu_get_history(self):
226
menu = self.get_menu()
227
children = menu.children()
228
item = menu.get_active()
230
for i in range(len(children)):
231
if children[i] == item:
236
class GtkBuildScript(buildscript.BuildScript):
237
def __init__(self, config, module_list):
238
buildscript.BuildScript.__init__(self, config, module_list)
239
self.current_module = None
242
self.terminal_command = self._getTerminalCommand()
244
self.terminal_command = "gnome-terminal"
246
def _getTerminalCommand(self):
247
client = gconf.client_get_default()
248
command = client.get_string("/desktop/gnome/applications/terminal/exec")
251
def message(self, msg, module_num = -1):
252
'''shows a message to the screen'''
255
module_num = self.module_num
256
dialog = gtk.MessageDialog(buttons=gtk.BUTTONS_OK, message_format=msg)
261
def set_action(self, action, module, module_num=-1, action_target=None):
263
module_num = self.module_num
264
if not action_target:
265
action_target = module.name
266
if self.current_module != module and self.current_module != None:
267
self.current_module._build_text_buffer = self.build_text
268
self.build_text = gtk.TextBuffer(self.tag_table)
269
self.build_text_view.set_buffer(self.build_text)
270
self.iter = self.build_text.get_end_iter()
271
self.current_module = module
273
num_modules = len(self.modulelist)
275
self.build_progress.set_fraction(module_num / float(num_modules))
276
self.build_progress.set_text('%d of %d modules'
277
% (module_num, num_modules))
279
self.window.set_title('[%d/%d] %s %s' % (module_num, num_modules, action, module.name))
280
self.current_status_label.set_text('%s %s' % (action, module.name))
282
def _runEventLoop(self):
283
while gtk.events_pending():
286
def _printToBuildOutput(self, output):
287
self.iter = self.build_text.get_end_iter()
288
self.build_text.insert(self.iter, output)
289
self.build_text.move_mark (self.ins_mark, self.iter)
290
self.build_text_view.scroll_to_mark (self.ins_mark, 0.0, True, 0.5, 0.5)
292
def _printToWarningOutput(self, output):
293
self.build_text.insert_with_tags_by_name(self.iter, output, "warning")
295
def _pauseBuild(self):
296
return self.pause_button.get_active()
298
def _makeNonBlocking(self, fd):
299
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
300
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY)
303
def execute(self, command, hint=None, cwd=None, extra_env=None):
304
'''executes a command, and returns the error code'''
309
'shell': isinstance(command, (str,unicode)),
310
'stdin': subprocess.PIPE,
311
'stdout': subprocess.PIPE,
312
'stderr': subprocess.PIPE,
318
if extra_env is not None:
319
kws['env'] = os.environ.copy()
320
kws['env'].update(extra_env)
92
for module in full_module_list:
93
if isinstance(module, MetaModule):
94
if module.name.endswith('-deprecations'):
95
# skip the deprecation meta modules, nobody want them
97
iter = self.modules_list_model.append((module.name, False, ''))
98
self.modules_list_model.append(('', True, ''))
99
self.modules_list_model.append((_('Others...'), False, ''))
101
for module in self.config.modules:
102
iter = self.add_extra_module_to_model(module)
103
if not self.default_module_iter:
104
self.default_module_iter = iter
106
def add_extra_module_to_model(self, module, startat=''):
107
# lookup selected module in current modules list
108
for row in self.modules_list_model:
109
row_value = self.modules_list_model.get(row.iter, 0)[0]
110
if row_value == module:
111
self.modules_list_model.set_value(row.iter, 2, startat)
114
# add selected module in the list
115
if self.modules_list_model.get(self.modules_list_model[-3].iter, 1)[0] is False:
116
# there is no user-added modules at the moment, add a separator row
117
self.modules_list_model.insert_before(
118
self.modules_list_model[-2].iter, ('', True, ''))
119
iter = self.modules_list_model.insert_before(
120
self.modules_list_model[-2].iter, (module, False, startat))
124
def on_delete_event(self, *args):
128
os.kill(self.child_pid, signal.SIGKILL)
133
self.set_border_width(5)
134
app_vbox = gtk.VBox(spacing=5)
136
self.module_hbox = gtk.HBox(spacing=5)
137
app_vbox.pack_start(self.module_hbox, fill=False, expand=False)
140
label.set_markup('<b>%s</b>' % _('Choose Module:'))
141
self.module_hbox.pack_start(label, fill=False, expand=False)
143
self.module_combo = gtk.ComboBox(self.modules_list_model)
144
cell = gtk.CellRendererText()
145
self.module_combo.pack_start(cell, True)
146
self.module_combo.add_attribute(cell, 'text', 0)
147
self.module_combo.changed_signal_id = self.module_combo.connect(
148
'changed', self.on_module_selection_changed_cb)
150
self.module_combo.set_row_separator_func(lambda x,y: x.get(y, 1)[0])
151
self.module_hbox.pack_start(self.module_combo, fill=True)
153
separator = gtk.VSeparator()
154
self.module_hbox.pack_start(separator, fill=False, expand=False)
155
preferences = gtk.Button(stock=gtk.STOCK_PREFERENCES)
156
preferences.connect('clicked', self.on_preferences_cb)
157
self.module_hbox.pack_start(preferences, fill=False, expand=False)
159
self.progressbar = gtk.ProgressBar()
160
self.progressbar.set_text(_('Build Progress'))
161
app_vbox.pack_start(self.progressbar, fill=False, expand=False)
163
expander = gtk.Expander(_('Terminal'))
164
expander.set_expanded(False)
165
app_vbox.pack_start(expander, fill=False, expand=False)
166
sclwin = gtk.ScrolledWindow()
167
sclwin.set_size_request(-1, 300)
168
sclwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
171
self.terminal = vte.Terminal()
172
self.terminal.connect('child-exited', self.on_vte_child_exit_cb)
174
os.environ['TERM'] = 'dumb' # avoid commands printing vt sequences
175
self.terminal = gtk.TextView()
176
self.terminal.set_size_request(800, -1)
177
textbuffer = self.terminal.get_buffer()
178
terminal_bold_tag = textbuffer.create_tag('bold')
179
terminal_bold_tag.set_property('weight', pango.WEIGHT_BOLD)
180
terminal_mono_tag = textbuffer.create_tag('mono')
181
terminal_mono_tag.set_property('family', 'Monospace')
182
terminal_stdout_tag = textbuffer.create_tag('stdout')
183
terminal_stdout_tag.set_property('family', 'Monospace')
184
terminal_stderr_tag = textbuffer.create_tag('stderr')
185
terminal_stderr_tag.set_property('family', 'Monospace')
186
terminal_stderr_tag.set_property('foreground', 'red')
187
terminal_stdin_tag = textbuffer.create_tag('stdin')
188
terminal_stdin_tag.set_property('family', 'Monospace')
189
terminal_stdin_tag.set_property('style', pango.STYLE_ITALIC)
190
self.terminal.set_editable(False)
191
self.terminal.set_wrap_mode(gtk.WRAP_CHAR)
192
sclwin.add(self.terminal)
193
self.terminal_sclwin = sclwin
195
self.error_hbox = self.create_error_hbox()
196
app_vbox.pack_start(self.error_hbox, fill=False, expand=False)
198
buttonbox = gtk.HButtonBox()
199
buttonbox.set_layout(gtk.BUTTONBOX_END)
200
app_vbox.pack_start(buttonbox, fill=False, expand=False)
202
# Translators: This is a button label (to start build)
203
self.build_button = gtk.Button(_('Start'))
204
self.build_button.connect('clicked', self.on_build_cb)
205
buttonbox.add(self.build_button)
207
button = gtk.Button(stock=gtk.STOCK_HELP)
208
button.connect('clicked', self.on_help_cb)
209
buttonbox.add(button)
210
buttonbox.set_child_secondary(button, True)
213
self.error_hbox.hide()
217
def create_error_hbox(self):
218
error_hbox = gtk.HBox(False, 8)
220
image.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_BUTTON)
221
error_hbox.pack_start(image, fill=False, expand=False)
222
image.set_alignment(0.5, 0.5)
224
vbox = gtk.VBox(False, 6)
225
error_hbox.pack_start (vbox, True, True, 0)
227
self.error_label = gtk.Label()
228
vbox.pack_start(self.error_label, fill=True, expand=True)
229
self.error_label.set_use_markup(True)
230
self.error_label.set_line_wrap(True)
231
self.error_label.set_alignment(0, 0.5)
234
second_hbox = gtk.HBox()
235
vbox.pack_start(second_hbox)
237
self.error_resolution_model = gtk.ListStore(str, str)
238
self.error_combo = gtk.ComboBox(self.error_resolution_model)
239
self.error_combo.connect('changed', self.on_error_resolution_changed_cb)
240
self.error_combo.set_row_separator_func(lambda x,y: (x.get(y, 0)[0] == ''))
241
cell = gtk.CellRendererText()
242
self.error_combo.pack_start(cell, True)
243
self.error_combo.add_attribute(cell, 'markup', 0)
244
second_hbox.pack_start(self.error_combo)
246
self.error_apply_button = gtk.Button(stock = gtk.STOCK_APPLY)
247
self.error_apply_button.set_sensitive(False)
248
self.error_apply_button.connect('clicked', self.on_resolution_apply_clicked)
249
second_hbox.pack_start(self.error_apply_button, fill=False, expand=False)
253
def on_error_resolution_changed_cb(self, *args):
254
iter = self.error_combo.get_active_iter()
257
if not self.error_resolution_model.get(iter, 1)[0]:
259
self.error_apply_button.set_sensitive(True)
261
def on_resolution_apply_clicked(self, *args):
262
self.error_apply_button.set_sensitive(False)
263
iter = self.error_combo.get_active_iter()
266
self.error_resolution = self.error_resolution_model.get(iter, 1)[0]
268
def on_help_cb(self, *args):
269
gtk.show_uri(gtk.gdk.screen_get_default(),
270
'ghelp:jhbuild', gtk.get_current_event_time())
272
def on_preferences_cb(self, *args):
273
if not self.preference_dialog:
274
self.preference_dialog = PreferencesDialog(self)
275
self.preference_dialog.show()
276
self.preference_dialog.present()
278
def on_build_cb(self, *args):
279
if self.preference_dialog:
280
self.preference_dialog.hide()
281
if not self.orig_modulelist:
282
modules = [self.modules_list_model.get(
283
self.module_combo.get_active_iter(), 0)[0]]
285
self.modulelist = self.module_set.get_module_list(modules,
286
self.config.skip, tags = self.config.tags,
287
ignore_suggests=self.config.ignore_suggests)
289
self.orig_modulelist = None
291
startat = self.modules_list_model.get(self.module_combo.get_active_iter(), 2)[0]
293
while self.modulelist and self.modulelist[0].name != startat:
294
del self.modulelist[0]
297
def on_module_selection_changed_cb(self, *args):
298
old_selected_iter = self.active_iter
299
last_iter = self.modules_list_model[-1].iter
300
self.active_iter = self.module_combo.get_active_iter()
301
if self.modules_list_model.get_path(
302
self.active_iter) != self.modules_list_model.get_path(last_iter):
304
# "Others..." got clicked, modal dialog to let the user select a
306
current_module = self.modules_list_model.get(old_selected_iter, 0)[0]
307
dlg = SelectModulesDialog(self, current_module)
309
if response != gtk.RESPONSE_OK:
311
self.module_combo.set_active_iter(old_selected_iter)
313
selected_module = dlg.selected_module
314
startat = dlg.startat
317
iter = self.add_extra_module_to_model(selected_module, startat)
318
self.module_combo.set_active_iter(iter)
320
def is_build_paused(self):
324
if gtk.main_level() == 0 and self.orig_modulelist:
325
# gtkui called from a "normal" command, not from jhbuild gui
326
self.modulelist = self.orig_modulelist
328
self.build_button.emit('clicked')
329
while gtk.events_pending():
333
except AttributeError:
323
p = subprocess.Popen(command, **kws)
325
raise CommandError(str(e))
328
self._makeNonBlocking(p.stdout)
329
self._makeNonBlocking(p.stderr)
332
read_set = [p.stdout, p.stderr]
335
# Allow the frontend to get a little time
338
rlist, wlist, xlist = select.select(read_set, [], [], 0)
340
if p.stdout in rlist:
341
chunk = p.stdout.read()
344
read_set.remove(p.stdout)
345
self._printToBuildOutput(chunk)
347
if p.stderr in rlist:
348
chunk = p.stderr.read()
351
read_set.remove(p.stderr)
352
self._printToWarningOutput(chunk)
354
# See if we should pause the current command
355
if not build_paused and self._pauseBuild():
356
print ("Pausing this guy, sending os.kill to %d", p.pid)
357
os.kill(p.pid, signal.SIGSTOP)
359
elif build_paused and not self._pauseBuild():
360
print ("Continuing him")
361
os.kill(p.pid, signal.SIGCONT)
336
self.rc = buildscript.BuildScript.build(self)
337
except ExitRequestedException:
368
341
def start_build(self):
369
self.window.show_all()
342
self.build_button.set_sensitive(False)
343
self.module_hbox.set_sensitive(False)
370
345
def end_build(self, failures):
371
if len(failures) == 0:
372
self.message('success')
374
self.message('the following modules were not built:\n%s'
375
% ', '.join(failures))
346
self.progressbar.set_fraction(1)
347
self.progressbar.set_text(_('Build Completed'))
348
self.build_button.set_sensitive(True)
349
self.module_hbox.set_sensitive(True)
376
351
def start_module(self, module):
377
# Remember where we are in case something fails
379
client = gconf.client_get_default()
380
client.set_string("/apps/jhbuild/start_at_module", module)
382
def handle_error(self, module, state, nextstate, error, altstates):
383
'''Ask the user what to do about an error.
385
Returns one of ERR_RERUN, ERR_CONT or ERR_GIVEUP.''' #"
387
if not self.config.interact:
390
dialog = gtk.Dialog('Error during %s for module %s' % (state, module.name))
391
dialog.add_button('_Try %s Again' % state, 1)
392
dialog.add_button('_Ignore Error', 2)
393
dialog.add_button('_Skip Module', 3)
394
dialog.add_button('_Terminal', 4)
396
for i, altstate in enumerate(altstates):
397
dialog.add_button('Go to %s' % altstate, i + 5)
399
text_view = gtk.TextView()
400
text_view.set_buffer(self.build_text)
401
text_view.set_wrap_mode(gtk.WRAP_WORD)
403
scroller = gtk.ScrolledWindow()
404
scroller.add(text_view)
405
dialog.vbox.pack_start(scroller)
407
scroller.set_size_request(-1, 250)
408
scroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
409
scroller.set_shadow_type(gtk.SHADOW_IN)
410
scroller.set_border_width(12)
352
idx = [x.name for x in self.modulelist].index(module)
353
self.progressbar.set_fraction((1.0*idx) / len(self.modulelist))
355
self.terminal.feed('%s*** %s ***%s\n\r' % (t_bold, module, t_reset))
357
textbuffer = self.terminal.get_buffer()
358
textbuffer.insert_with_tags_by_name(
359
textbuffer.get_end_iter(), '*** %s ***\n' % module, 'bold')
360
mark = textbuffer.create_mark('end', textbuffer.get_end_iter(), False)
361
self.terminal.scroll_to_mark(mark, 0.05, True, 0.0, 1.0)
363
def end_module(self, module, failed):
364
self.error_hbox.hide()
366
def set_action(self, action, module, module_num=-1, action_target=None):
367
self.progressbar.set_text('%s %s' % (action, action_target or module.name))
369
def message(self, msg, module_num=-1):
372
def handle_error(self, module, phase, nextphase, error, altphases):
373
summary = _('Error during phase %(phase)s of %(module)s') % {
374
'phase': phase, 'module':module.name}
376
error_message = error.args[0]
377
self.message('%s: %s' % (summary, error_message))
380
self.message(summary)
382
if not self.is_active():
383
self.set_urgency_hint(True)
384
self.notify.notify(summary=summary, body=error_message,
385
icon=gtk.STOCK_DIALOG_ERROR, expire=5)
387
self.error_label.set_markup('<b>%s</b>' % _(summary))
388
self.error_resolution_model.clear()
389
iter = self.error_resolution_model.append(
390
('<i>%s</i>' % _('Pick an Action'), ''))
391
self.error_resolution_model.append(('', ''))
392
self.error_resolution_model.append(
393
(_('Rerun phase %s') % phase, phase))
395
self.error_resolution_model.append(
396
(_('Ignore error and continue to %s') % nextphase, nextphase))
398
self.error_resolution_model.append(
399
(_('Ignore error and continue to next module'), '_done'))
400
self.error_resolution_model.append(
401
(_('Give up on module'), 'fail'))
402
for altphase in altphases:
404
altphase_label = _(getattr(getattr(module, 'do_' + altphase), 'label'))
405
except AttributeError:
406
altphase_label = altphase
407
self.error_resolution_model.append(
408
(_('Go to phase "%s"') % altphase_label, altphase))
409
self.error_resolution_model.append(('', ''))
410
self.error_resolution_model.append(
411
(_('Open Terminal'), 'shell'))
413
self.error_combo.set_active_iter(iter)
414
self.error_hbox.set_sensitive(True)
415
self.error_hbox.show_all()
416
self.error_resolution = None
414
#self.message('error during %s for module %s' % (state, module.name))
416
text_view.scroll_to_iter(self.build_text.get_end_iter(), 0.0, True, 0.5, 0.5)
423
# If the dialog was destroyed, interpret that as try again.
424
if val in (1, gtk.RESPONSE_NONE, gtk.RESPONSE_DELETE_EVENT):
431
command = 'cd %s; %s' % (module.get_builddir(self),
432
self.terminal_command)
435
return altstates[val - 5]
437
def _createWindow(self):
438
glade_filename = get_glade_filename()
439
self.glade = gtk.glade.XML(glade_filename)
441
self.window = self.glade.get_widget("BuildWindow")
442
self.build_progress = self.glade.get_widget("BuildProgressBar")
443
self.build_text_view = self.glade.get_widget("BuildText")
444
self.current_status_label = self.glade.get_widget("CurrentStatusLabel")
445
self.pause_button = self.glade.get_widget("BuildPauseButton")
446
self.cancel_button = self.glade.get_widget("BuildCancelButton")
447
#self.expander_button = self.glade.get_widget("ExpanderButton")
448
#self.expander_arrow = self.glade.get_widget("ExpanderArrow")
450
self.window.connect('destroy', lambda win: sys.exit())
451
self.cancel_button.connect('clicked', lambda button: sys.exit())
452
#self.expander_button.connect('activate',
454
self.tag_table = gtk.TextTagTable()
455
self.build_text = gtk.TextBuffer(self.tag_table)
456
self.warning_tag = self.build_text.create_tag("warning")
457
self.warning_tag.set_property("foreground", "red")
458
self.build_text_view.set_buffer(self.build_text)
459
self.build_text_view.set_wrap_mode(gtk.WRAP_WORD)
460
self.iter = self.build_text.get_end_iter()
461
self.ins_mark = self.build_text.create_mark ("jhbuild-mark", self.iter, True);
463
BUILD_SCRIPT = GtkBuildScript
419
self.error_resolution = None
420
while gtk.events_pending():
424
if not self.error_resolution:
426
self.set_urgency_hint(False)
427
if self.error_resolution == 'shell':
428
# set back combobox to "Pick an action"
429
self.error_combo.set_active_iter(iter)
431
cmd = ['gnome-terminal', '--working-directory', module.get_builddir(self)]
432
os.execvp('gnome-terminal', cmd)
435
if self.error_resolution == '_done':
436
self.error_resolution = None
437
# keep the error hox visible during all of this module duration
438
self.error_hbox.set_sensitive(False)
439
return self.error_resolution
441
def execute(self, command, hint=None, cwd=None, extra_env=None):
443
raise CommandError(_('No command given'))
445
if isinstance(command, (str, unicode)):
446
short_command = command.split()[0]
448
short_command = command[0]
451
textbuffer = self.terminal.get_buffer()
453
if isinstance(command, (str, unicode)):
454
self.terminal.get_buffer().insert_with_tags_by_name(
455
textbuffer.get_end_iter(),
456
' $ ' + command + '\n', 'stdin')
458
self.terminal.get_buffer().insert_with_tags_by_name(
459
textbuffer.get_end_iter(),
460
' $ ' + ' '.join(command) + '\n', 'stdin')
464
'shell': isinstance(command, (str,unicode)),
465
'stdin': subprocess.PIPE,
466
'stdout': subprocess.PIPE,
467
'stderr': subprocess.PIPE,
473
if extra_env is not None:
474
kws['env'] = os.environ.copy()
475
kws['env'].update(extra_env)
478
p = subprocess.Popen(command, **kws)
480
raise CommandError(str(e))
481
self.child_pid = p.pid
485
def make_non_blocking(fd):
486
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
487
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY)
489
make_non_blocking(p.stdout)
490
make_non_blocking(p.stderr)
493
read_set = [p.stdout, p.stderr]
496
# Allow the frontend to get a little time
497
while gtk.events_pending():
500
raise ExitRequestedException()
502
rlist, wlist, xlist = select.select(read_set, [], [], 0)
504
if p.stdout in rlist:
505
chunk = p.stdout.read()
508
read_set.remove(p.stdout)
509
textbuffer.insert_with_tags_by_name(
510
textbuffer.get_end_iter(), chunk, 'stdout')
512
if p.stderr in rlist:
513
chunk = p.stderr.read()
516
read_set.remove(p.stderr)
517
textbuffer.insert_with_tags_by_name(
518
textbuffer.get_end_iter(), chunk, 'stderr')
520
if textbuffer.get_line_count() > 200:
521
textbuffer.delete(textbuffer.get_start_iter(),
522
textbuffer.get_iter_at_line_offset(
523
textbuffer.get_line_count()-200, 0))
525
mark = textbuffer.get_mark('end')
527
textbuffer.move_mark(mark, textbuffer.get_end_iter())
529
mark = textbuffer.create_mark('end', textbuffer.get_end_iter(), False)
531
if self.terminal_sclwin.get_vadjustment().upper == \
532
(self.terminal_sclwin.size_request()[1] +
533
self.terminal_sclwin.get_vadjustment().get_value()):
534
# currently at the bottom of the textview, therefore scroll
536
self.terminal.scroll_to_mark(mark, 0.05, True, 0.0, 1.0)
538
# See if we should pause the current command
539
if not build_paused and self.is_build_paused():
540
os.kill(p.pid, signal.SIGSTOP)
542
elif build_paused and not self.is_build_paused():
543
os.kill(p.pid, signal.SIGCONT)
549
self.child_pid = None
552
if isinstance(command, (str, unicode)):
553
self.terminal.feed(' $ ' + command + '\n\r')
554
command = [os.environ.get('SHELL', '/bin/sh'), '-c', command]
556
self.terminal.feed(' $ ' + ' '.join(command) + '\n\r')
559
if extra_env is not None:
560
env = os.environ.copy()
561
env.update(extra_env)
562
kws['envv'] = ['%s=%s' % x for x in env.items()]
565
kws['directory'] = cwd
567
self.vte_fork_running = True
568
self.vte_child_exit_status = None
569
# In earlier python-vte versions,
570
# - the environment had to be passed as a sequence of strings
571
# ("FOO=1", "BAR=2") (GNOME bug 583078)
572
# - directory keyword could not be set to None (GNOME bug 583129)
573
# The bugs have been fixed, but for compatibility reasons the old
574
# compatibility code is still in place.
575
self.child_pid = self.terminal.fork_command(
576
command=command[0], argv=command, **kws)
577
while self.vte_fork_running:
580
raise ExitRequestedException()
581
self.child_pid = None
582
if os.WIFEXITED(self.vte_child_exit_status):
583
rc = os.WEXITSTATUS(self.vte_child_exit_status)
584
elif os.WIFSIGNALED(self.vte_child_exit_status):
585
raise CommandError(_('%(command)s died with signal %(rc)s') % {
586
'command': short_command, 'rc': os.WTERMSIG(rc)})
589
raise CommandError(_('%(command)s returned with an error code (%(rc)s)') % {
590
'command': short_command, 'rc': rc})
592
def on_vte_child_exit_cb(self, terminal):
593
self.vte_fork_running = False
594
self.vte_child_exit_status = self.terminal.get_child_exit_status()
597
class SelectModulesDialog(gtk.Dialog):
598
def __init__(self, parent, default_module=None):
599
gtk.Dialog.__init__(self, '', parent)
605
for module_row in self.modules_model:
606
if self.modules_model.get(module_row.iter, 0)[0] == default_module:
607
self.treeview.get_selection().select_iter(module_row.iter)
608
self.treeview.scroll_to_cell(
609
self.modules_model.get_path(module_row.iter))
611
self.connect('response', self.on_response_cb)
613
def create_model(self):
614
self.modules_model = gtk.ListStore(str)
615
modules = [x.name for x in self.app.module_set.get_full_module_list()]
616
for module in sorted(modules, lambda x,y: cmp(x.lower(), y.lower())):
617
self.modules_model.append((module,))
619
def create_frame(self, label, child):
620
frame = gtk.Frame('')
621
frame.set_border_width(3)
622
frame.set_shadow_type(gtk.SHADOW_NONE)
623
frame.get_label_widget().set_markup('<b>%s</b>' % label)
625
alignment = gtk.Alignment()
626
alignment.set_padding(0, 0, 12, 0)
636
sclwin = gtk.ScrolledWindow()
637
sclwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
638
sclwin.set_size_request(-1, 200)
639
vbox.pack_start(self.create_frame(_('Module'), sclwin))
641
self.treeview = gtk.TreeView(self.modules_model)
642
self.treeview.set_headers_visible(False)
643
sclwin.add(self.treeview)
644
selection = self.treeview.get_selection()
645
selection.connect('changed', self.on_selection_changed_cb)
647
renderer = gtk.CellRendererText()
648
tv_col = gtk.TreeViewColumn('', renderer, text=0)
649
tv_col.set_expand(True)
650
tv_col.set_min_width(200)
651
self.treeview.append_column(tv_col)
653
self.startat_model = gtk.ListStore(str)
654
self.combo_startat = gtk.ComboBox(self.startat_model)
655
cell = gtk.CellRendererText()
656
self.combo_startat.pack_start(cell, True)
657
self.combo_startat.add_attribute(cell, 'text', 0)
658
vbox.pack_start(self.create_frame(_('Start At'), self.combo_startat))
662
self.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
663
self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
665
def on_selection_changed_cb(self, selection, *args):
666
iter = selection.get_selected()[1]
667
self.selected_module = self.modules_model.get(iter, 0)[0]
670
old_start_at_iter = self.combo_startat.get_active_iter()
671
new_active_iter = None
672
if old_start_at_iter:
673
old_start_at = self.startat_model.get(old_start_at_iter, 0)[0]
675
self.startat_model.clear()
676
modulelist = self.app.module_set.get_module_list([self.selected_module],
677
ignore_suggests=self.app.config.ignore_suggests)
678
for module in modulelist:
679
iter = self.startat_model.append((module.name,))
680
if module.name == old_start_at:
681
new_active_iter = iter
684
self.combo_startat.set_active_iter(new_active_iter)
686
self.combo_startat.set_active_iter(self.startat_model[0].iter)
688
def on_response_cb(self, dlg, response_id, *args):
689
if response_id != gtk.RESPONSE_OK:
692
old_start_at_iter = self.combo_startat.get_active_iter()
694
if old_start_at_iter:
695
self.startat = self.startat_model.get(old_start_at_iter, 0)[0]
697
return gtk.RESPONSE_OK
699
class PreferencesDialog(gtk.Dialog):
700
def __init__(self, parent, default_module=None):
701
gtk.Dialog.__init__(self, _('Preferences'), parent)
704
self.connect('response', self.on_response_cb)
705
self.connect('delete-event', self.on_response_cb)
708
vbox = gtk.VBox(spacing=5)
709
vbox.set_border_width(5)
713
('nonetwork', _('Disable network access')),
714
('alwaysautogen', _('Always run autogen.sh')),
715
('nopoison', _('Don\'t poison modules on failure'))):
716
checkbutton = gtk.CheckButton(label)
717
checkbutton.set_active(getattr(self.app.config, key))
718
checkbutton.connect('toggled', self.on_toggled_key, key)
719
vbox.pack_start(checkbutton, expand=False, fill=False)
722
self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
724
def on_toggled_key(self, checkbutton, key):
725
setattr(self.app.config, key, checkbutton.get_active())
727
def on_response_cb(self, *args):
729
self.app.preference_dialog = None
732
BUILD_SCRIPT = AppWindow