James Hunt has proposed merging lp:~jamesodhunt/upstart/upstart-monitor into lp:upstart.
Requested reviews: Upstart Reviewers (upstart-reviewers) For more details, see: https://code.launchpad.net/~jamesodhunt/upstart/upstart-monitor/+merge/153839 Initial implementation of upstart-monitor event gui+cli tool. See: http://ifdeflinux.blogspot.co.uk/2013/03/a-basic-upstart-events-gui-and-cli-tool.html -- https://code.launchpad.net/~jamesodhunt/upstart/upstart-monitor/+merge/153839 Your team Upstart Reviewers is requested to review the proposed merge of lp:~jamesodhunt/upstart/upstart-monitor into lp:upstart.
=== modified file 'ChangeLog' --- ChangeLog 2013-03-15 12:51:25 +0000 +++ ChangeLog 2013-03-18 15:24:25 +0000 @@ -1,3 +1,4 @@ +<<<<<<< TREE 2013-03-15 James Hunt <[email protected]> * extra/man/file-event.7: Simplify language. @@ -20,6 +21,23 @@ * extra/man/file-event.7: New man page. * extra/man/upstart-file-bridge.8: New man page. +======= +2013-03-18 James Hunt <[email protected]> + + * configure.ac: Added scripts/data/Makefile. + * scripts/Makefile.am: Added SUBDIRS=data. + * scripts/data/Makefile.am: New Makefile. + * scripts/data/upstart-monitor.desktop: Desktop file for + upstart-monitor. + +2013-03-13 James Hunt <[email protected]> + + * scripts/man/upstart-monitor.8: New manpage. + * scripts/upstart-monitor.py: New cli+gui tool to monitor + Upstart events. + * scripts/Makefile.am: Updated for upstart-monitor. + +>>>>>>> MERGE-SOURCE 2013-03-04 James Hunt <[email protected]> * init/session.c: session_from_dbus(): Fixed off-by-one === modified file 'configure.ac' --- configure.ac 2013-03-04 11:57:18 +0000 +++ configure.ac 2013-03-18 15:24:25 +0000 @@ -101,6 +101,6 @@ AC_CONFIG_FILES([ Makefile intl/Makefile dbus/Makefile init/Makefile util/Makefile conf/Makefile extra/Makefile doc/Makefile contrib/Makefile po/Makefile.in - scripts/Makefile ]) + scripts/Makefile scripts/data/Makefile ]) AC_CONFIG_HEADERS([config.h]) AC_OUTPUT === modified file 'scripts/Makefile.am' --- scripts/Makefile.am 2011-06-01 14:57:41 +0000 +++ scripts/Makefile.am 2013-03-18 15:24:25 +0000 @@ -1,8 +1,11 @@ ## Process this file with automake to produce Makefile.in +SUBDIRS = data + EXTRA_DIST = \ initctl2dot.py \ - init-checkconf.sh + init-checkconf.sh \ + upstart-monitor.py dist_man_MANS = \ man/initctl2dot.8 \ === added directory 'scripts/data' === added file 'scripts/data/Makefile.am' --- scripts/data/Makefile.am 1970-01-01 00:00:00 +0000 +++ scripts/data/Makefile.am 2013-03-18 15:24:25 +0000 @@ -0,0 +1,24 @@ +desktopdir = $(datadir)/applications +desktop_DATA = upstart-monitor.desktop + +icondir = $(datadir)/icons/hicolor/scalable/apps +icon = upstart-monitor.svg +icon_DATA = $(icon) + +$(icon): $(top_srcdir)/doc/upstart-logo.svg + cp $< $@ + +EXTRA_DIST = $(desktop_DATA) + +install-icon: + mkdir -p $(DESTDIR)$(pkgdatadir)/icons/ + $(INSTALL_DATA) $(icon) $(DESTDIR)$(pkgdatadir)/icons/ + +uninstall-icon: + rm -f $(DESTDIR)$(pkgdatadir)/icons/$(icon) + +install-data-local: install-icon +uninstall-local: uninstall-icon + +clean-local: + rm -f $(icon) === added file 'scripts/data/upstart-monitor.desktop' --- scripts/data/upstart-monitor.desktop 1970-01-01 00:00:00 +0000 +++ scripts/data/upstart-monitor.desktop 2013-03-18 15:24:25 +0000 @@ -0,0 +1,8 @@ +[Desktop Entry] +Encoding=UTF-8 +Comment=Upstart Event Monitor +Name=upstart-monitor +Exec=upstart-monitor +Icon=upstart-monitor +Type=Application +Categories=GNOME;GTK;Utility; === added file 'scripts/man/upstart-monitor.8' --- scripts/man/upstart-monitor.8 1970-01-01 00:00:00 +0000 +++ scripts/man/upstart-monitor.8 2013-03-18 15:24:25 +0000 @@ -0,0 +1,81 @@ +.TH upstart\-monitor 8 2013-03-13 upstart +.\" +.SH NAME +upstart\-monitor \- Display system and session Upstart events +.\" +.SH SYNOPSIS +.B upstart\-monitor +.RI [ OPTIONS ]... +.\" +.SH DESCRIPTION +.B upstart\-monitor +displays Upstart system events or Upstart session events using either a +command-line or graphical interface. +.\" +.SH OPTIONS +.\" +.TP +.BR \-d " \fIdestination\fP" " , " \-\-destination=\fIdestination\fP +Specify the endpoint to connect to. Valid destinations are +.IR session\-socket ", " +.IR session\-bus ", " +.IR system\-socket " and " +.IR system-bus "." +.\" +.TP +.B \-\-help +Show brief usage summary. +.\" +.TP +.BR \-n " , " \-\-no-gui +Run in command-line mode. +.\" +.TP +.BR \-s " , " \-\-separator +Specify alternate field separator to use for command-line output +(default is a single tab character). +.\" +.SH NOTES +.\" +.IP \(bu 4 +By default, +.B upstart\-monitor +will attempt to start in a graphical mode unless +.B \-\-no\-gui +is specified. However, if it is unable to display a graphical interface, +it will display a warning message and automatically revert to the +command-line interface. +.\" +.IP \(bu 4 +When no command-line option (that affects the destination) is specified, +.B upstart\-monitor +will attempt to connect to the Session Init (destination +\fIsession\-socket\fR) and display session events. In this mode, it +will display both session events +.I and +system events, assuming the +.BR upstart-event-bridge (8) +is running. + +If invoked with no arguments from within a non-Upstart session +environment it will attempt to connect to Upstart running as process ID +1 (destination \fIsystem\-bus\fR) and will only display system events. +.\" +.SH AUTHOR +Written by James Hunt +.RB < [email protected] > +.\" +.SH BUGS +Report bugs at +.RB < https://launchpad.net/ubuntu/+source/upstart/+bugs > +.\" +.SH COPYRIGHT +Copyright \(co 2013 Canonical Ltd. +.PP +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +.SH SEE ALSO +.BR init (5) +.BR init (8) +.BR upstart-events (7) +.BR upstart-event-bridge (8) === added file 'scripts/upstart-monitor.py' --- scripts/upstart-monitor.py 1970-01-01 00:00:00 +0000 +++ scripts/upstart-monitor.py 2013-03-18 15:24:25 +0000 @@ -0,0 +1,687 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# vim: set fileencoding=utf-8 +#--------------------------------------------------------------------- +# Copyright © 2013 Canonical Ltd. +# +# Author: James Hunt <[email protected]> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2, as +# published by the Free Software Foundation. +# +# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +#--------------------------------------------------------------------- +# TODO: +# +# - misc +# - handle_clear_data() default message should use gettext +# - gui +# - Gtk.STOCK_MEDIA_PLAY toggle +# - menus +# - Edit->Copy +# - Edit->Select +# - Edit->Select All +# - Edit->Copy All +# - Connection +# - Choose from 4 connection types. +# - View +# - Show/Hide index+time columns +# - Pause of auto-scroll +#--------------------------------------------------------------------- + +import os +import sys +import gettext +import argparse +import signal +import dbus +import dbus.mainloop.glib +from datetime import datetime + +VERSION = 0.1 +COPYRIGHT = 'Copyright © 2013 Canonical Ltd.' +DESCRIPTION = 'Simple Upstart Event Monitor' +NAME = 'upstart-monitor' +AUTHORS = [ + 'James Hunt <[email protected]>' +] +WEBSITE = 'http://upstart.ubuntu.com' + +cli = False + +try: + from gi.repository import Gtk, Gdk, GdkPixbuf, GLib +except ImportError: + gettext.install(NAME) + print("%s: %s" % (_('WARNING'), _('GUI modules not available - falling back to CLI')), file=sys.stderr) + cli = True + +""" +Simple command-line and GUI event monitor for Upstart. +""" + +# If this file does not exist or is not readable... +LICENSE_FILE = 'aa/usr/share/common-licenses/GPL-2' + +# ... display this text instead. +LICENSE = """ +http://www.gnu.org/ +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2, as +published by the Free Software Foundation. + +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 Street, Fifth Floor, Boston, MA 02110-1301 USA. +""" + +#------------------------------ + +DEFAULT_WIN_SIZE_WIDTH = 600 +DEFAULT_WIN_SIZE_HEIGHT = 200 + +DEFAULT_LOGO_SIZE_WIDTH = 150 +DEFAULT_LOGO_SIZE_HEIGHT = 150 + +DEFAULT_OUTPUT_FILE = 'upstart-events.txt' + +# key=type : value=description +destinations = \ +{ + 'system-bus' : 'D-Bus system bus', + 'session-bus' : 'D-Bus session bus', + 'system-socket' : 'D-Bus system socket', + 'session-socket' : 'D-Bus session socket' +} + +#------------------------------ + +# well-known address for Upstart running as PID 1 +INIT_SOCKET = 'unix:abstract=/com/ubuntu/upstart' + +# Address of Session Inits private socket +SESSION_SOCKET = os.environ.get('UPSTART_SESSION') + +UI_INFO = """ +<ui> + <menubar name='MenuBar'> + + <menu action='FileMenu'> + <menuitem action='FileNew'/> + <menuitem action='FileSave'/> + <menuitem action='FileSaveAs'/> + <separator/> + <menuitem action='FileQuit'/> + </menu> + +<!-- + <menu action='EditMenu'> + <menuitem action='EditCopy'/> + </menu> + + <menu action='OptionsMenu'> + <menuitem action='OptionsAutoScroll'/> + <menu action='ConnectionMenu'> + <menuitem action='System Bus'/> + <menuitem action='System Socket'/> + <menuitem action='Session Bus'/> + <menuitem action='Session Socket'/> + </menu> + </menu> + +--> + <menu action='HelpMenu'> + <menuitem action='HelpAbout'/> + </menu> + + </menubar> + + <popup name='ContextMenu'> + <menuitem action='ContextCopy'/> + </popup> +</ui> +""" + + +def format_event(*args): + """ + Format raw D-Bus event details. + + Returns: event and quoted event environment tuple. + """ + quoted_env = [] + + event = args[0] + + # unfortunately, quotes are stripped so they need to be re-added + # to preserve whitespace in the environment variable values. + raw_env = args[1] + + for e in raw_env: + f = e.split('=') + quoted_env.append("%s='%s'" % (f[0], ''.join(f[1:]))) + + env = ' '.join(str(e) for e in quoted_env) + + return event, env + + +def cmdline_event_handler(*args): + """ + format event data for command-line display + """ + global cmdline_args + + event, env = format_event(*args) + now = datetime.now().strftime("%F %T.%f") + event_str = "%s %s" % (event, env) if env else event + sep = cmdline_args.separator if cmdline_args.separator else "\t" + print("%s%s%s" % (now, sep, event_str)) + + +class UpstartEventsGui(Gtk.Window): + """ + GUI Upstart Event monitor. + """ + global bus + global cmdline_args + + auto_scroll = True + need_save = False + + # value of cell containing event details that user has + # right-clicked over + context_value = None + + def add_row(self, event, event_env): + """ + Add new row to view. + """ + self.data_index += 1 + now = datetime.now().strftime("%F %T.%f") + event_str = "%s %s" % (event, event_env) if event_env else event + + row = [self.data_index, now, event_str] + self.liststore.append(row) + + + def event_handler(self, *args): + """ + Upstart has emitted an event so create a new row in the view. + """ + event, env = format_event(*args) + self.add_row(event, env) + + # New data arrived since last save (if any). + self.need_save = True + + + def register_cb(self): + """ + Callback to register a D-Bus callback whenever Upstart emits an + event. + """ + # register a D-Bus handler + bus.add_signal_receiver(self.event_handler, + dbus_interface='com.ubuntu.Upstart0_6', + signal_name="EventEmitted") + + # deregister this callback + return False + + + def treeview_changed(self, widget, event, data=None): + """ + Allow GUI to auto-scroll. + """ + adj = self.scrolled_window.get_vadjustment() + adj.set_value(adj.get_upper() - adj.get_page_size()) + + + def ask_question(self, msg): + """ + Ask a question. + + @msg: message to display. + + Returns: True if user answered positively, else False. + """ + dialog = Gtk.MessageDialog(self, + Gtk.DialogFlags.DESTROY_WITH_PARENT, + Gtk.MessageType.QUESTION, + Gtk.ButtonsType.YES_NO, + msg) + response = dialog.run() + dialog.destroy() + return True if response == Gtk.ResponseType.YES else False + + + def show_dialog(self, msg): + """ + Display an "ok" dialog which the user must click. + + @msg: message to display. + """ + dialog = Gtk.MessageDialog(self, + Gtk.DialogFlags.DESTROY_WITH_PARENT, + Gtk.MessageType.ERROR, + Gtk.ButtonsType.OK, + msg) + dialog.run() + dialog.destroy() + + + def show_about(self): + """ + Show an About dialog. + """ + about = Gtk.AboutDialog() + about.set_program_name(NAME) + about.set_version("%s %s" % (_('Version'), VERSION)) + about.set_copyright(COPYRIGHT) + about.set_comments(DESCRIPTION) + about.set_authors(AUTHORS) + about.set_website(WEBSITE) + + try: + with open(LICENSE_FILE, 'r') as f: + license = f.read() + except IOError: + license = LICENSE + + about.set_license(license) + about.set_logo(self.icon_pixbuf) + about.run() + about.destroy() + + + def on_button_clear_clicked(self, widget): + """ + Clear cached event data (also clears GUI window). + """ + if self.handle_clear_data(): + self.liststore.clear() + self.data_index = 1 + self.need_save = False + + def on_button_pause_clicked(self, widget): + """ + Toggle auto-scroll. + """ + if self.auto_scroll: + self.treeview.disconnect(self.auto_scroll_handler) + self.auto_scroll = False + else: + self.auto_scroll_handler = \ + self.treeview.connect('size-allocate', self.treeview_changed) + self.auto_scroll = True + + + def save_data(self, path): + """ + Write received event data to specified path. + """ + try: + fh = open(path, 'w') + except IOError: + self.show_dialog('%s: %s' % (_('Error saving file'), path)) + + for row in self.liststore: + fh.write("%d\t%s\t%s\n" % (row[0], row[1], row[2])) + fh.close() + + # All data was written + self.need_save = False + + + def handle_save(self, filename=None): + """ + Display a file chooser dialog to allow user to select a filename to + hold the cached event data. + """ + # no data yet + if not len(self.liststore): + self.show_dialog(_('No events to save')) + return + + if filename != None: + path = filename + self.save_data(path) + return + + file_chooser = Gtk.FileChooserDialog(_('Save File'), self.get_toplevel(), + Gtk.FileChooserAction.SAVE, + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_SAVE, Gtk.ResponseType.ACCEPT)) + + file_chooser.set_current_name(DEFAULT_OUTPUT_FILE) + + response = file_chooser.run() + + if response != Gtk.ResponseType.ACCEPT: + file_chooser.destroy() + return + + path = file_chooser.get_filename() + + self.save_data(path) + file_chooser.destroy() + + def handle_quit(self): + """ + Quit application; if unsaved data exists, prompt user. + """ + + if self.handle_clear_data('Quit without saving?'): + Gtk.main_quit() + + def on_button_quit_clicked(self, widget): + """ + Handle quit request. + """ + self.handle_quit() + + + def on_button_save_clicked(self, widget): + """ + Handle save request. + """ + self.handle_save() + + # FIXME: default message should use gettext + def handle_clear_data(self, message='Clear data without saving?'): + """ + Handle potentially clearing of cached events. + + Returns: True if user is happy to clear the data, else False. + """ + if len(self.liststore) and self.need_save: + answer = self.ask_question(message) + return answer + else: + # no data would be lost so allow action + return True + + def activate_action(self, action, user_data=None): + """ + Main menu-callback-handling method. + """ + name = action.get_name() + + if name == 'FileNew': + if self.handle_clear_data(): + self.liststore.clear() + self.data_index = 1 + self.need_save = False + elif name == 'FileSave': + self.handle_save(DEFAULT_OUTPUT_FILE) + elif name == 'FileSaveAs': + self.handle_save() + elif name == 'FileQuit': + self.handle_quit() + elif name == 'HelpAbout': + self.show_about() + elif name == 'ContextCopy': + # Save event details from cell text to clipboard + clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) + clipboard.set_text(self.context_value, -1) + + def create_ui_manager(self): + """ + Errrm... create the UI Manager. + """ + ui_manager = Gtk.UIManager() + + # Throws exception if something went wrong + ui_manager.add_ui_from_string(UI_INFO) + + # Add the accelerator group to the toplevel window + accelgroup = ui_manager.get_accel_group() + self.add_accel_group(accelgroup) + return ui_manager + + def on_button_press_event(self, treeview, event): + """ + Handle mouse button press events. + """ + if event.type == Gdk.EventType.BUTTON_PRESS and event.button == 3: + x = int(event.x) + y = int(event.y) + path_info = treeview.get_path_at_pos(x, y) + if path_info: + path, col, cell_x, cell_y = path_info + + model = treeview.get_model() + model_iter = model.get_iter(path) + + # Save the event details from the selected cell + # (event is 3rd column (zero-indexed)). + self.context_value = model.get_value (model_iter, 2) + + treeview.grab_focus() + treeview.set_cursor(path, col, 0) + + # Display context menu + self.popup.popup(None, None, None, None, event.button, event.time) + return True + + + def __init__(self): + """ + Setup. + """ + Gtk.Window.__init__(self, title=DESCRIPTION) + + main_menu_action_entries = ( + ('FileMenu', None, 'File'), + ('FileNew', Gtk.STOCK_NEW, 'New', '<control>N', + _('Clear events'), self.activate_action), + ('FileSave', Gtk.STOCK_SAVE, 'Save', '<control>S', + _('Save events to default file'), self.activate_action), + ('FileSaveAs', Gtk.STOCK_SAVE_AS, 'Save As', None, + _('Save events to specified file'), self.activate_action), + ('FileQuit', Gtk.STOCK_QUIT, 'Quit', '<control>Q', + _('Exit application'), self.activate_action), + + ('HelpMenu', None, 'Help'), + ('HelpAbout', Gtk.STOCK_HELP, 'About', '<control>A', + _('Application details'), self.activate_action), + ) + + context_menu_action_entries = ( + ('ContextCopy', Gtk.STOCK_COPY, 'Copy', '<control>C', + _('Copy'), self.activate_action), + ) + + self.data_index = 0 + + self.set_default_size(DEFAULT_WIN_SIZE_WIDTH, DEFAULT_WIN_SIZE_HEIGHT) + self.set_resizable(True) + + theme = Gtk.IconTheme.get_default() + self.icon_pixbuf = theme.load_icon(NAME, 128, Gtk.IconLookupFlags.GENERIC_FALLBACK) + self.set_icon(self.icon_pixbuf) + + action_group = Gtk.ActionGroup('UpstartMonitorActions') + action_group.add_actions(main_menu_action_entries) + action_group.add_actions(context_menu_action_entries) + + ui_manager = self.create_ui_manager() + ui_manager.insert_action_group(action_group) + + menubar = ui_manager.get_widget("/MenuBar") + + # data types we'll be using in each column + self.liststore = Gtk.ListStore(int, str, str) + + GLib.idle_add(self.register_cb) + + self.box = Gtk.Box(spacing=6, orientation=Gtk.Orientation.VERTICAL) + + self.scrolled_window = Gtk.ScrolledWindow() + self.scrolled_window.set_policy(Gtk.PolicyType.ALWAYS, Gtk.PolicyType.ALWAYS) + + self.treeview = Gtk.TreeView(model=self.liststore) + + # columns are zero-based + self.treeview.set_search_column(2) + + self.treeview.set_headers_clickable(True) + + if self.auto_scroll: + self.auto_scroll_handler = \ + self.treeview.connect('size-allocate', self.treeview_changed) + + renderer_text = Gtk.CellRendererText() + + # XXX: mark column as editable, but do NOT connect the 'edited' + # signal. This allows the user to select the text and copy it, + # but they cannot modify it. + renderer_editabletext = Gtk.CellRendererText() + renderer_editabletext.set_property('editable', True) + + column_index = Gtk.TreeViewColumn(_('Index'), renderer_text, text=0) + column_index.set_resizable(True) + self.treeview.append_column(column_index) + + column_time = Gtk.TreeViewColumn(_('Time'), renderer_text, text=1) + column_time.set_resizable(True) + self.treeview.append_column(column_time) + + column_event = Gtk.TreeViewColumn(_('Event and environment'), + renderer_editabletext, text=2) + column_event.set_resizable(True) + + self.popup = ui_manager.get_widget("/ContextMenu") + self.treeview.connect('button-press-event', self.on_button_press_event) + + self.treeview.append_column(column_event) + + # stops column titles from scrolling along with the data + self.scrolled_window.add(self.treeview) + + self.button_clear = Gtk.Button(stock=Gtk.STOCK_CLEAR) + self.button_clear.connect('clicked', self.on_button_clear_clicked) + + # FIXME: toggle to Gtk.STOCK_MEDIA_PLAY + self.button_pause = Gtk.Button(stock=Gtk.STOCK_MEDIA_PAUSE) + self.button_pause.connect('clicked', self.on_button_pause_clicked) + + self.button_save = Gtk.Button(stock=Gtk.STOCK_SAVE) + self.button_save.connect('clicked', self.on_button_save_clicked) + + self.button_quit = Gtk.Button(stock=Gtk.STOCK_QUIT) + self.button_quit.connect('clicked', self.on_button_quit_clicked) + + self.label_connected = Gtk.Label('%s %s' % (_('Connected to'), + destinations[cmdline_args.destination])) + self.label_connected.set_justify(Gtk.Justification.RIGHT) + + self.buttons_box = Gtk.Box(spacing=6, orientation=Gtk.Orientation.HORIZONTAL) + self.buttons_box.pack_start(self.button_clear, False, True, 0) + self.buttons_box.pack_start(self.button_pause, False, True, 0) + self.buttons_box.pack_start(self.button_save, False, True, 0) + self.buttons_box.pack_start(self.button_quit, False, True, 0) + self.buttons_box.pack_start(self.label_connected, True, True, 0) + + self.box.pack_start(menubar, False, False, 0) + self.box.pack_start(self.scrolled_window, True, True, 0) + self.box.pack_end(self.buttons_box, False, False, 0) + self.add(self.box) + + + def text_edited(self, widget, path, text): + self.liststore[path][1] = text + + +def main(): + """ + Parse arguments and run either the command-line or the GUI monitor. + """ + global bus + global cmdline_args + global cli + + gettext.install(NAME) + + parser = argparse.ArgumentParser(description=_('Upstart Event Monitor')) + + parser.add_argument('-n', '--no-gui', + action='store_true', + help=_('run in command-line mode')) + + parser.add_argument('-s', '--separator', + help=_('field separator to use for command-line output')) + + parser.add_argument('-d', '--destination', + choices=destinations.keys(), + help=_('connect to Upstart via specified D-Bus route')) + + cmdline_args = parser.parse_args() + + # allow interrupt + signal.signal(signal.SIGINT, signal.SIG_DFL) + + dbus.set_default_main_loop(dbus.mainloop.glib.DBusGMainLoop()) + + if not cmdline_args.destination: + # If no destination specified, attempt to connect to session + # if running under a Session Init, else connect to the system + # bus (since this allows even non-priv users to see events). + if SESSION_SOCKET: + cmdline_args.destination = 'session-socket' + else: + cmdline_args.destination = 'system-bus' + + if cmdline_args.destination == 'system-bus': + bus = dbus.SystemBus() + elif cmdline_args.destination == 'session-bus': + bus = dbus.SessionBus() + elif cmdline_args.destination == 'system-socket': + socket = INIT_SOCKET + bus = dbus.connection.Connection(socket) + elif cmdline_args.destination == 'session-socket': + socket = SESSION_SOCKET + bus = dbus.connection.Connection(socket) + if cmdline_args.no_gui or not os.environ.get('DISPLAY'): + cli = True + + # dynamically load GUI elements so we can fall back to the + # command-line version if we cannot display a GUI + if cli == True: + # register a D-Bus handler + bus.add_signal_receiver(cmdline_event_handler, dbus_interface='com.ubuntu.Upstart0_6', + signal_name='EventEmitted') + loop = GLib.MainLoop() + print('# Upstart Event Monitor (%s)' % _('console mode')) + print('#') + print('# %s %s' % (_('Connected to'), destinations[cmdline_args.destination])) + print('#') + print('# %s' % _('Columns: time, event and environment')) + print('') + loop.run() + else: + win = UpstartEventsGui() + win.connect('delete-event', Gtk.main_quit) + win.show_all() + Gtk.main() + + +if __name__ == '__main__': + # Allow _() to be called from this point onwards + gettext.install(NAME) + + main()
-- upstart-devel mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/upstart-devel
