219 lines
7.9 KiB
Python
Executable File
219 lines
7.9 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
# LADITools - Linux Audio Desktop Integration Tools
|
|
# ladilog - A log viewer for your Linux Audio Desktop
|
|
# Copyright (C) 2011-2012 Alessio Treglia <quadrispro@ubuntu.com>
|
|
# Copyright (C) 2007-2010, Marc-Olivier Barre <marco@marcochapeau.org>
|
|
# Copyright (C) 2007-2009, Nedko Arnaudov <nedko@arnaudov.name>
|
|
#
|
|
# 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 <http://www.gnu.org/licenses/>.
|
|
|
|
import os
|
|
import sys
|
|
import signal
|
|
from subprocess import Popen, PIPE
|
|
import pty
|
|
from signal import SIGTERM
|
|
import termios
|
|
import tty
|
|
import gettext
|
|
import argparse
|
|
|
|
sig_handler = signal.getsignal(signal.SIGTERM)
|
|
signal.signal(signal.SIGINT, sig_handler)
|
|
|
|
from laditools import _gettext_domain
|
|
gettext.install(_gettext_domain)
|
|
|
|
from laditools import get_version_string
|
|
from laditools import LadiConfiguration
|
|
|
|
from gi.repository import Gtk
|
|
from gi.repository import GObject
|
|
from gi.repository import Vte
|
|
|
|
from laditools.gtk import find_data_file
|
|
|
|
timeout_add = GObject.timeout_add
|
|
|
|
# Default configuration
|
|
max_lines_default = 100
|
|
|
|
# Output the last <lines> 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 = LadiConfiguration ()
|
|
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)
|
|
sys.stderr.write( _("Skipping '%s' because it does not exist\n") % log['logfile_path'])
|
|
else:
|
|
sys.stderr.write( _("Watching %s\n") % log['logfile_path'])
|
|
sys.stderr.flush()
|
|
|
|
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(find_data_file("ladilog_ui.ui"))
|
|
sys.stderr.write( _("Loading interface from %s\n") % find_data_file("ladilog_ui.ui"))
|
|
sys.stderr.flush()
|
|
# Get the ui ready for action
|
|
self.event_dict = {"on_ladilog_ui_destroy" : self.on_quit,
|
|
"on_ladilog_ui_delete" : self.on_delete,
|
|
"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)
|
|
|
|
self.ui = ui = builder.get_object("ladilog_ui")
|
|
self.logview_notebook = builder.get_object ("ladilog_notebook")
|
|
# Create our terminal and display it
|
|
for log in self.log_files:
|
|
log['scrolled_window'] = sw = Gtk.ScrolledWindow()
|
|
log['term'] = term = Vte.Terminal.new ()
|
|
sw.set_policy(hscrollbar_policy=Gtk.PolicyType.AUTOMATIC,
|
|
vscrollbar_policy=Gtk.PolicyType.ALWAYS)
|
|
sw.add(term)
|
|
sw.show()
|
|
term.set_scroll_on_output(True)
|
|
log["tab_label"] = Gtk.Label(label=log["name"])
|
|
|
|
self.logview_notebook.append_page(log["scrolled_window"],
|
|
log["tab_label"])
|
|
|
|
# Make it do something...
|
|
for log in self.log_files:
|
|
try:
|
|
log['log_file'] = open(log['logfile_path'], "rb")
|
|
sys.stderr.write (_("Opening %s...\n") % log['logfile_path'])
|
|
lines = read_last(log['log_file'], self.max_lines)
|
|
for line in lines:
|
|
line = line.strip('\r\n') + '\r\n'
|
|
log["term"].feed(line, -1)
|
|
except ValueError:
|
|
sys.stderr.write( _("You called Popen with invalid arguments... dumbass\n") )
|
|
except:
|
|
sys.stderr.write( _("Unexpected error: %s\n") % (sys.exc_info ()[0]))
|
|
finally:
|
|
sys.stderr.flush()
|
|
|
|
ui.show_all()
|
|
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', -1)
|
|
line = log['log_file'].readline()
|
|
log['log_file'].seek(log['log_file'].tell())
|
|
return True
|
|
|
|
def on_delete(self, widget=None, data=None):
|
|
return False
|
|
|
|
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", -1)
|
|
|
|
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", -1)
|
|
|
|
def run (self):
|
|
Gtk.main ()
|
|
self.global_config.set_config_section ("ladilog", self.param_dict)
|
|
self.global_config.save ()
|
|
return 0
|
|
|
|
#try:
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser(description=_('JACK, ladish and a2jmidid log viewer'),
|
|
epilog=_('This program is part of the LADITools suite.'))
|
|
parser.add_argument('--version', action='version', version="%(prog)s " + get_version_string())
|
|
|
|
parser.parse_args()
|
|
ladilog().run()
|
|
sys.exit(0)
|
|
#except Exception, e:
|
|
# error = Gtk.MessageDialog(None,
|
|
# Gtk.DialogFlags.MODAL,
|
|
# Gtk.MessageType.ERROR,
|
|
# Gtk.ButtonsType.OK,
|
|
# _("Unexpected error\n\n") + repr(e))
|
|
# error.run()
|
|
# sys.exit(1)
|