nutools/tailor.py

120 lines
3.8 KiB
Python
Raw Normal View History

#!/usr/bin/env python
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
u"""Afficher des lignes en mettant en surbrillance certains patterns"""
import sys, subprocess, re
from collections import OrderedDict
def bluef(line, *ignored): return '\x1B[34m%s\x1B[0m' % line
def greenf(line, *ignored): return '\x1B[32m%s\x1B[0m' % line
def yellowf(line, *ignored): return '\x1B[33m%s\x1B[0m' % line
def redf(line, *ignored): return '\x1B[31m%s\x1B[0m' % line
def nonef(line, *ignored): return re.sub('\x1B\[.*?m', '', line)
DEFAULT_PATTERNS = OrderedDict([
(r'(?i)error', redf),
(r'(?i)warn(ing)?', yellowf),
(r'(?i)info', bluef),
(None, nonef),
])
FORMATS = OrderedDict([
('blue', bluef),
('green', greenf),
('yellow', yellowf),
('red', redf),
('none', nonef),
])
FORMAT_ALIASES = {
'b': 'blue',
'g': 'green',
'y': 'yellow',
'r': 'red',
'': 'none',
}
def strip_nl(s):
if s is None: return None
elif s.endswith("\r\n"): s = s[:-2]
elif s.endswith("\n"): s = s[:-1]
elif s.endswith("\r"): s = s[:-1]
return s
def run_tailor(inputfile=None, patterns=None):
if inputfile is None:
def next_line():
while True:
try: line = sys.stdin.readline()
except: break
if line == '': break
yield line
else:
def next_line():
p = subprocess.Popen(
['tail', '-f', inputfile],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
try: line = p.stdout.readline()
except: break
if line == '': break
yield line
if patterns is None: patterns = DEFAULT_PATTERNS
for line in next_line():
line = nonef(strip_nl(line))
func = False
mo = None
for p, f in patterns.items():
if p is None:
func = f
mo = None
break
mo = re.search(p, line)
if mo is not None:
func = f
break
if func is not False:
line = func(line, mo)
sys.stdout.write(line)
sys.stdout.write('\n')
if __name__ == '__main__':
from argparse import ArgumentParser, RawTextHelpFormatter
AP = ArgumentParser(
formatter_class=RawTextHelpFormatter,
usage=u"%(prog)s [-f INPUTFILE]",
description=__doc__,
)
AP.set_defaults(inputfile=None, patterns=None, defaults=True)
AP.add_argument('-f', '--follow', dest='inputfile',
help=u"Spécifier un fichier dont il faut suivre le contenu")
AP.add_argument('-e', '--pattern', action='append', dest='patterns', metavar='PATTERN:FORMAT',
help=u"""\
Ajouter une spécification de pattern et le format dans lequel il doit être affiché
Les formats valides sont: %s
Le format par défaut est red""" % ', '.join(FORMATS.keys()))
AP.add_argument('-z', '--no-defaults', action='store_const', dest='defaults', const=False,
help=u"Ne pas ajouter les patterns par défaut")
o = AP.parse_args()
if o.patterns is None:
patterns = DEFAULT_PATTERNS
else:
patterns = OrderedDict()
for pf in o.patterns:
mo = re.match('(.*):([a-zA-Z]*)$', pf)
if mo is not None:
p = mo.group(1)
of = mo.group(2)
else:
p = pf
of = 'red'
f = of.lower()
f = FORMAT_ALIASES.get(f, f)
if f not in FORMATS:
raise ValueError("%s: format invalide" % of)
patterns[p] = FORMATS[f]
if o.defaults: patterns.update(DEFAULT_PATTERNS)
run_tailor(o.inputfile, patterns)