Minor cleanup. Fix mulitple channels to match irkerhook's behaviour
[bzrirker.git] / irkerhook.py
1 # -*- coding: utf-8 -*-
2 # vim:fileencoding=utf-8 ai ts=4 sts=4 et sw=4
3 # Copyright 2012 Neil Muller
4 # GPL 2+ - see COPYING for details
5
6 from bzrlib.config import Option
7 import socket
8 import sys
9 import json
10
11
12 class IrkerSender(object):
13     """An irker message sender."""
14
15     def __init__(self, branch, revision_id, config):
16         self.config = config
17         self.branch = branch
18         self.repository = branch.repository
19         self._revision_id = revision_id
20         self.revision = None
21         self.revno = None
22
23     def _setup_revision_and_revno(self):
24         self.revision = self.repository.get_revision(self._revision_id)
25         self.revno = self.branch.revision_id_to_revno(self._revision_id)
26
27     def _format(self):
28         delta = self.branch.repository.get_revision_delta(self._revision_id)
29         files = []
30         [files.append(f) for (f,_,_) in delta.added]
31         [files.append(f) for (f,_,_) in delta.removed]
32         [files.append(f) for (_,f,_,_,_,_) in delta.renamed]
33         [files.append(f) for (f,_,_,_,_) in delta.modified]
34
35         fields = {
36             'project': self.project(),
37             'committer': self.revision.committer,
38             'repo': self.branch.nick,
39             'rev': '%d' % self.revno,
40             'files': ' '.join(files),
41             'logmsg': self.revision.get_summary(),
42             'url': self.url(),
43         }
44         for name, value in self.colours():
45             fields[name] = value
46         text = ('%(bold)s%(project)s:%(reset)s '
47                 '%(green)s%(committer)s%(reset)s '
48                 '%(repo)s * %(bold)s%(rev)s%(reset)s / '
49                 ' %(bold)s%(files)s%(reset)s: %(logmsg)s '
50                 '%(brown)s%(url)s%(reset)s' % fields)
51         return text
52
53     def url(self):
54         """What URL to display in the subject of the mail"""
55         url = self.config.get('irker_url')
56         if url is None:
57             url = self.config.get('public_branch')
58         if url is None:
59             url = self.branch.base
60         return url
61
62     def colours(self):
63         colour_style = self.config.get('irker_colours')
64         colours = {
65                 'bold': '',
66                 'green': '',
67                 'blue': '',
68                 'red': '',
69                 'yellow': '',
70                 'brown': '',
71                 'magenta': '',
72                 'cyan': '',
73                 'reset': '',
74                 }
75         # Vaues taken from irker's irkerhook.py
76         if colour_style == 'ANSI':
77             colours = {
78                     'bold': '\x1b[1m',
79                     'green': '\x1b[1;32m',
80                     'blue': '\x1b[1;34m',
81                     'red':  '\x1b[1;31m',
82                     'yellow': '\x1b[1;33m',
83                     'brown': '\x1b[33m',
84                     'magenta': '\x1b[35m',
85                     'cyan': '\x1b[36m',
86                     'reset': '\x1b[0m',
87                     }
88         elif colour_style == 'mIRC':
89             colours = {
90                     'bold': '\x02',
91                     'green': '\x0303',
92                     'blue': '\x0302',
93                     'red': '\x0305',
94                     'yellow': '\x0307',
95                     'brown': '\x0305',
96                     'magenta': '\x0306',
97                     'cyan': '\x0310',
98                     'reset': '\x0F',
99                     }
100         return colours.iteritems()
101
102     def project(self):
103         project = self.config.get('irker_project')
104         if project is None:
105             project = 'No Project name set'
106         return project
107
108     def send(self):
109         """Send the info to irkerd.
110         """
111         self.branch.lock_read()
112         self.repository.lock_read()
113         # These should become configurable at some point
114         default_server = 'localhost'
115         IRKER_PORT = 6659
116         try:
117             # Do this after we have locked, to make things faster.
118             self._setup_revision_and_revno()
119             channels = self.config.get('irker_channels')
120             if channels:
121                 channels = channels.split(',')
122             msg = unicode(self._format())
123             # We rely on the server truncating, rather than trying to be
124             # too fancy here
125             message = json.dumps({"to": channels, "privmsg": msg})
126             if channels:
127                 # We assume tcp, since I'm lazy, so we just grab that bit
128                 # of irker's code
129                 try:
130                     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
131                     sock.connect((default_server, IRKER_PORT))
132                     sock.sendall(message + "\n")
133                 except socket.error, e:
134                     sys.stderr.write("%s\n" % e)
135                 finally:
136                     sock.close()
137         finally:
138             self.repository.unlock()
139             self.branch.unlock()
140
141 opt_irker_url = Option('irker_url',
142     help='URL to mention for branch in messages.')
143 opt_irker_channels = Option('irker_channels',
144     help='Channel(s) to post commit messages to.')
145 opt_irker_colours = Option('irker_colours',
146     help='Colour option for irker.')
147 opt_irker_project = Option('irker_project',
148     help='Project name to use.')