Checks for tzc binary and punts if not found.
[snippets/.git] / barn-growl / barn-growl.py
1 #!/usr/bin/env python
2
3 """
4 Subscribes to zephyr via tzc and sends messages to notification drivers (growl or libnotify).
5 """
6
7 import sexpr
8 import os
9 import subprocess
10 import fcntl
11 import select
12 import sys
13 from abstfilter import AbstractConsumer
14 import optparse
15
16 class Notifier(AbstractConsumer):
17     def __init__(self, usegrowl, usenotify, useprint):
18         self.usegrowl = usegrowl
19         self.usenotify = usenotify
20         self.useprint = useprint
21         return
22     def feed(self, s):
23         if s is None or type(s) is type(''): return
24         d = dict([(ss[0], len(ss) > 2 and ss[2] or None) for ss in s])
25         if d['tzcspew'] == 'message':
26             zclass = d['class'].lower()
27             zinstance = d['instance'].lower()
28             zop = d['opcode'].lower()
29             zsender = d['sender'].lower()
30             zauth = d['auth'].lower() == 'yes'
31             ztime = ':'.join(d['time'].split(' ')[3].split(':')[0:2])
32             zmessage = d['message']
33             id = '%s/\n%s/\n%s\n %s' % (zclass, zinstance, zsender, ztime)
34             if zop == 'ping':
35                 header = '%s (%s)' % (id, zsender)
36                 message = '...'
37             elif zop == 'nil':
38                 header = '%s (%s)' % (id, len(zmessage) > 0 and zmessage[0] or zsender)
39                 message = '%s' % (len(zmessage) > 1 and zmessage[1] or '')
40             else:
41                 return
42             if self.useprint:
43                 print (id, header)
44                 print message
45             if self.usegrowl:
46                 growlnotify = ['growlnotify', '-a', 'MacZephyr', '-n', 'zephyr', '-d', id, '-t', header]
47                 g = subprocess.Popen(growlnotify, stdin=subprocess.PIPE)
48                 g.stdin.write(message)
49                 g.stdin.close()
50             if self.usenotify:
51                 notifysend = ['notify-send', header, message]
52                 subprocess.call(notifysend)
53     def close(self):
54         return
55
56 def main(argv):
57     parser = optparse.OptionParser(usage = '%prog [-s "username@machine"] (--growl | --notify | --print)',
58             description = __doc__.strip())
59     parser.add_option('-s', '--ssh',
60             type = 'string',
61             default = None,
62             dest = 'ssh',
63             help = 'optional remote host to run tzc')
64     parser.add_option('-g', '--growl',
65             action = 'store_true',
66             default = False,
67             dest = 'growl',
68             help = 'use growlnotify for output')
69     parser.add_option('-n', '--notify',
70             action = 'store_true',
71             default = False,
72             dest = 'notify',
73             help = 'use notify-send for output')
74     parser.add_option('-p', '--print',
75             action = 'store_true',
76             default = False,
77             dest = 'useprint',
78             help = 'use stdout for output')
79     opts, args = parser.parse_args()
80
81     usegrowl = opts.growl
82     usenotify = opts.notify
83     useprint = opts.useprint
84     if not usegrowl and not usenotify and not useprint:
85         parser.print_help(sys.stderr)
86         return 1
87     ssh = opts.ssh
88
89     if ssh is None:
90         retval = subprocess.call(['which', 'tzc'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
91         if retval:
92             print 'tzc not in path.  Please add -s username@machine to specify remote host.'
93             return 1
94
95     if ssh is not None:
96         command = "ssh -K %s 'tzc -si'" % ssh
97     else:
98         command = "tzc -si"
99     p = os.popen(command)
100     r = sexpr.SExprReader(Notifier(usegrowl, usenotify, useprint))
101
102     flags = fcntl.fcntl(p, fcntl.F_GETFL)
103     fcntl.fcntl(p, fcntl.F_SETFL, flags | os.O_NONBLOCK)
104
105     try:
106         while 1:
107             [i,o,e] = select.select([p], [], [], 5)
108             if i: s = p.read(1024)
109             else: s = ''
110
111             if s != '':
112                 r.feed(s)
113     except KeyboardInterrupt:
114         pass
115     return 0
116
117 if __name__ == "__main__":
118     sys.exit(main(sys.argv))