def unregister_popup(self, w, reg, is_group=False): window = gtk.MessageDialog( parent=self.window, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_NONE, message_format="Unregistering Suite " + reg + """ \nDelete suite definition directory too? (DANGEROUS!)""") window.add_button(gtk.STOCK_YES, gtk.RESPONSE_YES) window.add_button(gtk.STOCK_NO, gtk.RESPONSE_NO) window.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) response = window.run() window.destroy() if is_group: reg = '^' + reg + '\..*$' else: reg = '^' + reg + '$' if response == gtk.RESPONSE_YES: command = "cylc unregister -f -d " + reg elif response == gtk.RESPONSE_NO: command = "cylc unregister " + reg else: command = None if command: res, out = run_get_stdout(command) if not res: warning_dialog('\n'.join(out), self.window).warn()
def on_find_clicked(self, tv, e): needle = e.get_text() if not needle: return self.t.freeze = True self.freeze_button.set_active(True) self.freeze_button.set_label('Reconnect') if not self.search_warning_done: warning_dialog( "Find Next disconnects the live feed;" + " click Reconnect when you're done").warn() self.search_warning_done = True tb = tv.get_buffer() if needle == self.find_current: s = self.find_current_iter else: s, e = tb.get_bounds() tb.remove_all_tags(s, e) s = tb.get_end_iter() tv.scroll_to_iter(s, 0) try: f, l = s.backward_search(needle, gtk.TEXT_SEARCH_TEXT_ONLY) except: warning_dialog('"' + needle + '"' + " not found").warn() else: tag = tb.create_tag(None, background="#70FFA9") tb.apply_tag(tag, f, l) self.find_current_iter = f self.find_current = needle tv.scroll_to_iter(f, 0)
def copy_popup(self, w, reg, is_group=False): window = EntryDialog( parent=self.window, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK_CANCEL, message_format="Copy Suite " + reg + """To NAME,TOP_DIRECTORY""") out = window.run() window.destroy() if out: try: name, topdir = re.split(' *, *', out) except Exception, e: warning_dialog(str(e), self.window).warn() else: print name, topdir topdir = os.path.expanduser(os.path.expandvars(topdir)) print name, topdir command = "cylc cp " + reg + ' ' + name + ' ' + topdir print command res, out = run_get_stdout(command) if not res: warning_dialog('\n'.join(out), self.window).warn() elif out: info_dialog('\n'.join(out), self.window).inform()
def copy_popup(self, w, reg, is_group=False): window = EntryDialog(parent=self.window, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK_CANCEL, message_format="Copy Suite " + reg + """To NAME,TOP_DIRECTORY""") out = window.run() window.destroy() if out: try: name, topdir = re.split(' *, *', out) except Exception, e: warning_dialog(str(e), self.window).warn() else: print name, topdir topdir = os.path.expanduser(os.path.expandvars(topdir)) print name, topdir command = "cylc cp " + reg + ' ' + name + ' ' + topdir print command res, out = run_get_stdout(command) if not res: warning_dialog('\n'.join(out), self.window).warn() elif out: info_dialog('\n'.join(out), self.window).inform()
def unregister_popup(self, w, reg, is_group=False): window = gtk.MessageDialog(parent=self.window, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_NONE, message_format="Unregistering Suite " + reg + """ \nDelete suite definition directory too? (DANGEROUS!)""") window.add_button(gtk.STOCK_YES, gtk.RESPONSE_YES) window.add_button(gtk.STOCK_NO, gtk.RESPONSE_NO) window.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) response = window.run() window.destroy() if is_group: reg = '^' + reg + '\..*$' else: reg = '^' + reg + '$' if response == gtk.RESPONSE_YES: command = "cylc unregister -f -d " + reg elif response == gtk.RESPONSE_NO: command = "cylc unregister " + reg else: command = None if command: res, out = run_get_stdout(command) if not res: warning_dialog('\n'.join(out), self.window).warn()
def save(self, w, tv): tb = tv.get_buffer() start = tb.get_start_iter() end = tb.get_end_iter() txt = tb.get_text(start, end) dialog = gtk.FileChooserDialog( title='Save As', action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) filter_ = gtk.FileFilter() filter_.set_name("any") filter_.add_pattern("*") dialog.add_filter(filter_) response = dialog.run() if response != gtk.RESPONSE_OK: dialog.destroy() return False fname = dialog.get_filename() dialog.destroy() try: f = open(fname, 'wb') except IOError, x: warning_dialog(str(x), self.window).warn()
def save(self, w, tv): tb = tv.get_buffer() start = tb.get_start_iter() end = tb.get_end_iter() txt = tb.get_text(start, end) dialog = gtk.FileChooserDialog( title='Save As', action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) filter_ = gtk.FileFilter() filter_.set_name("any") filter_.add_pattern("*") dialog.add_filter(filter_) response = dialog.run() if response != gtk.RESPONSE_OK: dialog.destroy() return False fname = dialog.get_filename() dialog.destroy() try: f = open(fname, 'wb') except IOError, x: warning_dialog(str(x), self.window).warn()
def on_find_clicked(self, tv, e): needle = e.get_text() if not needle: return self.t.freeze = True self.freeze_button.set_active(True) self.freeze_button.set_label('Reconnect') if not self.search_warning_done: warning_dialog("Find Next disconnects the live feed;" + " click Reconnect when you're done").warn() self.search_warning_done = True tb = tv.get_buffer() if needle == self.find_current: s = self.find_current_iter else: s, e = tb.get_bounds() tb.remove_all_tags(s, e) s = tb.get_end_iter() tv.scroll_to_iter(s, 0) try: start, end = s.backward_search(needle, gtk.TEXT_SEARCH_TEXT_ONLY) except TypeError: # No search results. warning_dialog('"' + needle + '"' + " not found").warn() else: tag = tb.create_tag(None, background="#70FFA9") tb.apply_tag(tag, start, end) self.find_current_iter = start self.find_current = needle tv.scroll_to_iter(start, 0)
def run(self): """Invoke the command.""" command = shlex.split(self.cmd) try: self.proc = Popen(command, stdin=open(os.devnull), stdout=PIPE, stderr=STDOUT, preexec_fn=os.setpgrp) except OSError as exc: dialog = warning_dialog( "%s: %s" % (exc, " ".join(quote(item) for item in command))) gobject.idle_add(dialog.warn) return buf = "" while not self.quit and self.proc.poll() is None: try: self.pollable.poll() except (TypeError, AttributeError): pass if (self.freeze or not select.select([self.proc.stdout.fileno()], [], [], 100)): sleep(1) continue # Both self.proc.stdout.read(SIZE) and self.proc.stdout.readline() # can block. However os.read(FILENO, SIZE) should be fine after a # select.select(). try: data = os.read(self.proc.stdout.fileno(), self.READ_SIZE) except (IOError, OSError) as exc: dialog = warning_dialog( "%s: %s" % (exc, " ".join(quote(item) for item in command))) gobject.idle_add(dialog.warn) break if data: # Manage buffer, only add full lines to display to ensure # filtering and tagging work for line in data.splitlines(True): if not line.endswith("\n"): buf += line continue elif buf: line = buf + line buf = "" if (not self.filters or all(f.search(line) for f in self.filters)): gobject.idle_add(self.update_gui, line) sleep(0.01) self.stop()
def filter(self, filtr_e): if filtr_e == "": # reset self.start_updater() return filtr = filtr_e.get_text() try: re.compile(filtr) except: warning_dialog("Bad Regular Expression: " + filtr, self.window).warn() filtr_e.set_text("") self.start_updater() return self.start_updater(filtr)
def run(self): """Invoke the command.""" command = shlex.split(self.cmd) try: self.proc = Popen( command, stdin=open(os.devnull), stdout=PIPE, stderr=STDOUT, preexec_fn=os.setpgrp) except OSError as exc: dialog = warning_dialog("%s: %s" % ( exc, " ".join(quote(item) for item in command))) gobject.idle_add(dialog.warn) return buf = "" while not self.quit and self.proc.poll() is None: try: self.pollable.poll() except (TypeError, AttributeError): pass if ( self.freeze or not select.select([self.proc.stdout.fileno()], [], [], 100) ): sleep(1) continue # Both self.proc.stdout.read(SIZE) and self.proc.stdout.readline() # can block. However os.read(FILENO, SIZE) should be fine after a # select.select(). try: data = os.read(self.proc.stdout.fileno(), self.READ_SIZE) except (IOError, OSError) as exc: dialog = warning_dialog("%s: %s" % ( exc, " ".join(quote(item) for item in command))) gobject.idle_add(dialog.warn) break if data: # Manage buffer, only add full lines to display to ensure # filtering and tagging work for line in data.splitlines(True): if not line.endswith("\n"): buf += line continue elif buf: line = buf + line buf = "" if (not self.filters or all(f.search(line) for f in self.filters)): gobject.idle_add(self.update_gui, line) sleep(0.01) self.stop()
def reregister_popup(self, w, reg, is_group=False): window = EntryDialog(parent=self.window, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK_CANCEL, message_format="Reregister Suite " + reg + " As") rereg = window.run() window.destroy() if rereg: command = "cylc reregister " + reg + ' ' + rereg res, out = run_get_stdout(command) if not res: warning_dialog('\n'.join(out), self.window).warn()
def filter(self, filtr_e): if filtr_e == "": # reset self.start_updater() return filtr = filtr_e.get_text() try: re.compile(filtr) except re.error: warning_dialog("Bad Regular Expression: " + filtr, self.window).warn() filtr_e.set_text("") self.start_updater() return self.start_updater(filtr)
def update_gui(self, line): """Update the GUI viewer.""" try: line.decode('utf-8') except UnicodeDecodeError as exc: if self.has_warned_corrupt: return False self.has_warned_corrupt = True dialog = warning_dialog("Problem reading file:\n %s: %s" % (type(exc).__name__, exc)) gobject.idle_add(dialog.warn) return False for word, setting in self.TAGS.items(): rec, colour = setting if rec.match(line): if word not in self.tags: self.tags[word] = self.logbuffer.create_tag( None, foreground=colour) self.logbuffer.insert_with_tags(self.logbuffer.get_end_iter(), line, self.tags[word]) break else: self.logbuffer.insert(self.logbuffer.get_end_iter(), line) self.logview.scroll_to_iter(self.logbuffer.get_end_iter(), 0) return False
def update_gui(self, line): """Update the GUI viewer.""" try: line.decode('utf-8') except UnicodeDecodeError as exc: if self.has_warned_corrupt: return False self.has_warned_corrupt = True dialog = warning_dialog("Problem reading file:\n %s: %s" % (type(exc).__name__, exc)) gobject.idle_add(dialog.warn) return False for word, setting in self.TAGS.items(): rec, colour = setting if rec.match(line): if word not in self.tags: self.tags[word] = self.logbuffer.create_tag( None, foreground=colour) self.logbuffer.insert_with_tags( self.logbuffer.get_end_iter(), line, self.tags[word]) break else: self.logbuffer.insert(self.logbuffer.get_end_iter(), line) self.logview.scroll_to_iter(self.logbuffer.get_end_iter(), 0) return False
def reregister_popup(self, w, reg, is_group=False): window = EntryDialog( parent=self.window, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK_CANCEL, message_format="Reregister Suite " + reg + " As") rereg = window.run() window.destroy() if rereg: command = "cylc reregister " + reg + ' ' + rereg res, out = run_get_stdout(command) if not res: warning_dialog('\n'.join(out), self.window).warn()
def compare_popup(self, w, reg): window = EntryDialog(parent=self.window, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK_CANCEL, message_format="Compare Suite " + reg + " With") compare = window.run() window.destroy() if compare: command = "cylc diff " + reg + ' ' + compare res, out = run_get_stdout(command) if not res: warning_dialog('\n'.join(out), self.window).warn() else: # TODO: need a bigger scrollable window here! info_dialog('\n'.join(out), self.window).inform()
def compare_popup(self, w, reg): window = EntryDialog( parent=self.window, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK_CANCEL, message_format="Compare Suite " + reg + " With") compare = window.run() window.destroy() if compare: command = "cylc diff " + reg + ' ' + compare res, out = run_get_stdout(command) if not res: warning_dialog('\n'.join(out), self.window).warn() else: # TODO: need a bigger scrollable window here! info_dialog('\n'.join(out), self.window).inform()
def toggle_write_dot_frames(self): self.write_dot_frames = not self.write_dot_frames if self.write_dot_frames: # Create local share dir if necessary (could be a remote suite). try: mkdir_p(self.suite_share_dir) except Exception as exc: gobject.idle_add(warning_dialog( "%s\nCannot create graph frames directory." % (str(exc)) ).warn) self.write_dot_frames = False
def rotate_log(self, bt, go_older): if go_older: self.level += 1 else: self.level -= 1 if self.level < 0: warning_dialog( """ At newest rotation; reloading in case the suite has been restarted.""", self.window, ).warn() self.level = 0 # but update view in case user started suite after gui if self.current_log() not in os.listdir(self.dirname): if go_older: warning_dialog("Older log not available", self.window).warn() self.level -= 1 return else: warning_dialog("Newer log not available", self.window).warn() self.level += 1 return else: self.filename = self.current_log() self.update_view()
def on_find_clicked(self, e): tv = self.textview tb = tv.get_buffer() needle = e.get_text() if not needle: s, e = tb.get_bounds() tb.remove_tag(self.ftag, s, e) return self.stdout_updater.freeze = True self.freeze_button.set_active(True) self.freeze_button.set_label('_Reconnect') if not self.search_warning_done: warning_dialog( ("Find Next disconnects the live feed." + " Click Reconnect when you're done."), self.window).warn() self.search_warning_done = True if needle == self.find_current: s = self.find_current_iter else: s, e = tb.get_bounds() tb.remove_tag(self.ftag, s, e) s = tb.get_end_iter() tv.scroll_to_iter(s, 0) try: start, end = s.backward_search(needle, gtk.TEXT_SEARCH_VISIBLE_ONLY) except TypeError: # Search pattern not found. warning_dialog( '"' + needle + '"' + " not found", self.window).warn() else: tb.apply_tag(self.ftag, start, end) self.find_current_iter = start self.find_current = needle tv.scroll_to_iter(start, 0)
def rotate_log(self, bt, go_older): if go_older: self.level += 1 else: self.level -= 1 if self.level < 0: warning_dialog(""" At newest rotation; reloading in case the suite has been restarted.""", self.window).warn() self.level = 0 # but update view in case user started suite after gui if self.current_log() not in os.listdir(self.dirname): if go_older: warning_dialog("Older log not available", self.window).warn() self.level -= 1 return else: warning_dialog("Newer log not available", self.window).warn() self.level += 1 return else: self.filename = self.current_log() self.update_view()
def run(self): """Invoke the tailer.""" command = [] if ":" in self.filename: # remote user_at_host, filename = self.filename.split(':') if "@" in user_at_host: owner, host = user_at_host.split("@", 1) else: owner, host = (None, user_at_host) ssh = str(GLOBAL_CFG.get_host_item( "remote shell template", host, owner)).replace(" %s", "") command = shlex.split(ssh) + ["-n", user_at_host] cmd_tmpl = str(GLOBAL_CFG.get_host_item( "remote tail command template", host, owner)) else: filename = self.filename cmd_tmpl = str(GLOBAL_CFG.get_host_item( "local tail command template")) if self.cmd_tmpl: cmd_tmpl = self.cmd_tmpl command += shlex.split(cmd_tmpl % {"filename": filename}) try: self.proc = Popen( command, stdout=PIPE, stderr=STDOUT, preexec_fn=os.setpgrp) except OSError as exc: # E.g. ssh command not found dialog = warning_dialog("%s: %s" % ( exc, " ".join([quote(item) for item in command]))) gobject.idle_add(dialog.warn) return poller = select.poll() poller.register(self.proc.stdout.fileno()) buf = "" while not self.quit and self.proc.poll() is None: try: self.pollable.poll() except (TypeError, AttributeError): pass if self.freeze or not poller.poll(100): # 100 ms timeout sleep(1) continue # Both self.proc.stdout.read(SIZE) and self.proc.stdout.readline() # can block. However os.read(FILENO, SIZE) should be fine after a # poller.poll(). try: data = os.read(self.proc.stdout.fileno(), self.READ_SIZE) except (IOError, OSError) as exc: dialog = warning_dialog("%s: %s" % ( exc, " ".join([quote(item) for item in command]))) gobject.idle_add(dialog.warn) break if data: # Manage buffer, only add full lines to display to ensure # filtering and tagging work for line in data.splitlines(True): if not line.endswith("\n"): buf += line continue elif buf: line = buf + line buf = "" if (not self.filters or all([re.search(f, line) for f in self.filters])): gobject.idle_add(self.update_gui, line) sleep(0.01) self.stop()
def warn(self, msg): """Pop up a warning dialog; call on idle_add!""" warning_dialog(msg, self.info_bar.get_toplevel()).warn() return False
def graph_suite_popup(reg, cmd_help, defstartc, defstopc, graph_opts, gcapture_windows, tmpdir, template_opts, parent_window=None): """Popup a dialog to allow a user to configure their suite graphing.""" try: import xdot except ImportError as exc: warning_dialog(str(exc) + "\nGraphing disabled.", parent_window).warn() return False window = gtk.Window() window.set_border_width(5) window.set_title("cylc graph " + reg) window.set_transient_for(parent_window) window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) vbox = gtk.VBox() label = gtk.Label("[START]: ") start_entry = gtk.Entry() start_entry.set_max_length(14) if defstartc: start_entry.set_text(str(defstartc)) ic_hbox = gtk.HBox() ic_hbox.pack_start(label) ic_hbox.pack_start(start_entry, True) vbox.pack_start(ic_hbox) label = gtk.Label("[STOP]:") stop_entry = gtk.Entry() stop_entry.set_max_length(14) if defstopc: stop_entry.set_text(str(defstopc)) fc_hbox = gtk.HBox() fc_hbox.pack_start(label) fc_hbox.pack_start(stop_entry, True) vbox.pack_start(fc_hbox, True) cancel_button = gtk.Button("_Close") cancel_button.connect("clicked", lambda x: window.destroy()) ok_button = gtk.Button("_Graph") ok_button.connect( "clicked", lambda w: graph_suite(reg, start_entry.get_text(), stop_entry.get_text( ), graph_opts, gcapture_windows, tmpdir, template_opts, parent_window)) help_button = gtk.Button("_Help") help_button.connect("clicked", cmd_help, '', 'graph') hbox = gtk.HBox() hbox.pack_start(ok_button, False) hbox.pack_end(cancel_button, False) hbox.pack_end(help_button, False) vbox.pack_start(hbox) window.add(vbox) window.show_all()
def run(self): """Invoke the tailer.""" command = [] if ":" in self.filename: # remote user_at_host, filename = self.filename.split(':') if "@" in user_at_host: owner, host = user_at_host.split("@", 1) else: owner, host = (None, user_at_host) ssh = str( GLOBAL_CFG.get_host_item("remote shell template", host, owner)).replace(" %s", "") command = shlex.split(ssh) + ["-n", user_at_host] cmd_tmpl = str( GLOBAL_CFG.get_host_item("remote tail command template", host, owner)) else: filename = self.filename cmd_tmpl = str( GLOBAL_CFG.get_host_item("local tail command template")) if self.cmd_tmpl: cmd_tmpl = self.cmd_tmpl command += shlex.split(cmd_tmpl % {"filename": filename}) try: self.proc = Popen(command, stdout=PIPE, stderr=STDOUT, preexec_fn=os.setpgrp) except OSError as exc: # E.g. ssh command not found dialog = warning_dialog( "%s: %s" % (exc, " ".join([quote(item) for item in command]))) gobject.idle_add(dialog.warn) return poller = select.poll() poller.register(self.proc.stdout.fileno()) buf = "" while not self.quit and self.proc.poll() is None: try: self.pollable.poll() except (TypeError, AttributeError): pass if self.freeze or not poller.poll(100): # 100 ms timeout sleep(1) continue # Both self.proc.stdout.read(SIZE) and self.proc.stdout.readline() # can block. However os.read(FILENO, SIZE) should be fine after a # poller.poll(). try: data = os.read(self.proc.stdout.fileno(), self.READ_SIZE) except (IOError, OSError) as exc: dialog = warning_dialog( "%s: %s" % (exc, " ".join([quote(item) for item in command]))) gobject.idle_add(dialog.warn) break if data: # Manage buffer, only add full lines to display to ensure # filtering and tagging work for line in data.splitlines(True): if not line.endswith("\n"): buf += line continue elif buf: line = buf + line buf = "" if (not self.filters or all([re.search(f, line) for f in self.filters])): gobject.idle_add(self.update_gui, line) sleep(0.01) self.stop()