UnixWatchCommandOutput/pwatch.py
Joey Payne d20bfbd2f0 Created the UnixWatchCommandOutput file.
TODO: Add configurable time support.
      Possibly add the rest of watch's options as well
2012-10-24 20:17:46 -06:00

157 lines
4.6 KiB
Python
Executable file

#!/usr/bin/python
"""
Based on the code that
Lyle Scott, III wrote.
lyle@digitalfoo.net
Watches the output of a command in a
scrollable curses window.
"""
import curses
import sys
import random
import locale
import threading
import subprocess
import time
locale.setlocale(locale.LC_ALL,"")
class UnixWatchCommand:
DOWN = 1
UP = -1
SPACE_KEY = 32
ESC_KEY = 27
PREFIX_SELECTED = '-'
PREFIX_DESELECTED = ''
outputLines = []
screen = None
def __init__(self, command):
self.stop = threading.Event()
self.timer=threading.Thread(target=self.display)
self.command = ' '.join(command)
self.screen = curses.initscr()
curses.noecho()
curses.cbreak()
self.screen.keypad(1)
self.screen.border(0)
self.topLineNum = 0
self.highlightLineNum = 0
self.markedLineNums = []
self.getOutputLines()
self.timer.start()
self.run()
self.timer.join()
def display(self):
while not self.stop.is_set():
try:
self.displayScreen()
time.sleep(1)
except:
break
def run(self):
while True:
try:
self.displayScreen()
# get user command
c = self.screen.getch()
if c == curses.KEY_UP:
self.updown(self.UP)
elif c == curses.KEY_DOWN:
self.updown(self.DOWN)
elif c == self.SPACE_KEY:
self.markLine()
elif c == self.ESC_KEY:
self.stop.set()
break
except:
self.stop.set()
break
def markLine(self):
linenum = self.topLineNum + self.highlightLineNum
if linenum in self.markedLineNums:
self.markedLineNums.remove(linenum)
else:
self.markedLineNums.append(linenum)
def check_output(self, command):
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
universal_newlines=True)
output,stderr = process.communicate()
retcode = process.poll()
if retcode:
raise subprocess.CalledProcessError(retcode, command,
output=output[0])
return output.splitlines()
def getOutputLines(self):
self.outputLines = self.check_output(self.command)
self.nOutputLines = len(self.outputLines)
def displayScreen(self):
# clear screen
self.screen.clear()
self.getOutputLines()
# now paint the rows
top = self.topLineNum
bottom = self.topLineNum+curses.LINES
for (index,line,) in enumerate(self.outputLines[top:bottom]):
linenum = self.topLineNum + index
if linenum in self.markedLineNums:
prefix = self.PREFIX_SELECTED
else:
prefix = self.PREFIX_DESELECTED
#line = '%s %s' % (prefix, line,)
# highlight current line
if index != self.highlightLineNum:
self.screen.addstr(index, 0, line)
else:
self.screen.addstr(index, 0, line, curses.A_BOLD)
self.screen.refresh()
# move highlight up/down one line
def updown(self, increment):
nextLineNum = self.highlightLineNum + increment
# paging
if increment == self.UP and self.highlightLineNum == 0\
and self.topLineNum != 0:
self.topLineNum += self.UP
return
elif increment == self.DOWN and nextLineNum == curses.LINES\
and (self.topLineNum+curses.LINES) != self.nOutputLines:
self.topLineNum += self.DOWN
return
# scroll highlight line
if increment == self.UP and (self.topLineNum != 0 or\
self.highlightLineNum != 0):
self.highlightLineNum = nextLineNum
elif increment == self.DOWN and\
(self.topLineNum+self.highlightLineNum+1) != self.nOutputLines\
and self.highlightLineNum != curses.LINES:
self.highlightLineNum = nextLineNum
def restoreScreen(self):
curses.initscr()
curses.nocbreak()
curses.echo()
curses.endwin()
# catch any weird termination situations
def __del__(self):
self.restoreScreen()
if __name__ == '__main__':
ih = UnixWatchCommand(sys.argv[1:])