#!/usr/bin/python # LADITools - Linux Audio Desktop Integration Tools # ladilog - A log viewer for your Linux Audio Desktop # Copyright (C) 2007-2010, Marc-Olivier Barre # Copyright (C) 2007-2009, Nedko Arnaudov # # 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 3 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 . import os import sys from subprocess import Popen, PIPE import pty from signal import SIGTERM import termios import tty import gettext import laditools gettext.install(laditools.__name__) try: import imp imp.find_module('laditools') except ImportError: # Running from the build tree? sys.path.insert(0, os.path.join(sys.path[0], os.pardir)) import laditools try: from gobject import timeout_add import pygtk pygtk.require ('2.0') import gtk import vte except Exception, e: error = gtk.MessageDialog (None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("You need to get you dependencies right before you run this program. Ask your package maintainer why this is happening to you\n%s") % repr(e)) error.run () exit (1) # Default configuration max_lines_default = 100 # Output the last lines def read_last(lfile, lines): chunk_size = lines * 60 lfile.seek(0, 2) endpos = lfile.tell() pos = endpos - chunk_size if pos < 0: pos = 0 backlog = '' backlog_size = 0 lines += 1 while pos >= 0 and backlog_size <= lines: lfile.seek(pos, 0) s = lfile.read(chunk_size) pos = pos - chunk_size backlog_size += s.count("\n") backlog = s + backlog backlog = backlog.strip().split("\n") if len(backlog) > lines: backlog = backlog[-lines:] lfile.seek(endpos, 0) return backlog class ladilog(object): def __init__ (self): self.log_files = [ { 'name': 'JACK', 'config_name': 'jackdbus_log', 'config_default': os.sep.join([os.environ['HOME'], ".log", "jack", "jackdbus.log"]) }, { 'name': 'LADISH', 'config_name': 'ladish_log', 'config_default': os.sep.join([os.environ['HOME'], ".log", "ladish", "ladish.log"]) }, { 'name': 'A2J', 'config_name': 'a2j_log', 'config_default': os.sep.join([os.environ['HOME'], ".log", "a2j", "a2j.log"]) } ] # Handle the configuration self.global_config = laditools.config () self.param_dict = self.global_config.get_config_section ('ladilog') for log in self.log_files: if self.param_dict != None: if log['config_name'] not in self.param_dict: self.param_dict[log['config_name']] = log['config_default'] else: self.param_dict = {} self.param_dict[log['config_name']] = log['config_default'] if 'max_lines' not in self.param_dict: self.param_dict['max_lines'] = max_lines_default for log in self.log_files[:]: log['logfile_path'] = self.param_dict[log['config_name']] # skip logfiles that dont exist if not os.access(log['logfile_path'], os.R_OK): self.log_files.remove(log) print _("Skipping '%s' because it does not exist") % log['logfile_path'] else: print _("Watching '%s'") % log['logfile_path'] max_lines_text = self.param_dict['max_lines'] self.max_lines = int (max_lines_text) # Load the glade file builder = gtk.Builder() builder.add_from_file(laditools.find_data_file("ladilog_ui.ui")) # Get the ui ready for action self.event_dict = {"on_ladilog_ui_destroy" : self.on_quit, "on_close_button_clicked" : self.on_quit, "on_clear_button_clicked" : self.on_clear_text, "on_purge_button_clicked" : self.on_purge} builder.connect_signals(self.event_dict) # Create our terminal and display it for log in self.log_files: log['term'] = vte.Terminal () log["tab_label"] = gtk.Label (log["name"]) self.logview_notebook = builder.get_object ("ladilog_notebook") for log in self.log_files: log['term'].show () # Make it do something... for log in self.log_files: try: log['log_file'] = open(log['logfile_path'], "rb") lines = read_last(log['log_file'], self.max_lines) for line in lines: line = line.strip('\r\n') + '\r\n' log["term"].feed(line) except ValueError: print _("You called Popen with invalid arguments... dumbass") except: print _("Unexpected error:"), sys.exc_info ()[0] for log in self.log_files: self.logview_notebook.append_page (log["term"]) self.logview_notebook.set_tab_label (log["term"], log["tab_label"]) self.auto_updater = timeout_add(250, self.update) def update(self): # Append latest output to the buffer for log in self.log_files: line = log['log_file'].readline() while line: log["term"].feed(line + '\r') line = log['log_file'].readline() log['log_file'].seek(log['log_file'].tell()) return True def on_quit (self, data=None): gtk.main_quit () def on_clear_text (self, data=None): current_view = self.logview_notebook.get_current_page () self.log_files[current_view]["term"].feed ("\033[2J\033[;f") def on_purge (self, data=None): current_view = self.logview_notebook.get_current_page () # Opens the file in write anew mode thus clearing the file and close it right away open (self.log_files[current_view]['logfile_path'], "w+") self.log_files[current_view]["term"].feed ("\033[2J\033[;f") def run (self): gtk.main () self.global_config.set_config_section ("ladilog", self.param_dict) self.global_config.save () return 0 try: ladilog().run() except Exception, e: error = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Unexpected error\n\n") + repr(e)) error.run() exit(1)