summaryrefslogtreecommitdiff
path: root/pygerrit/stream.py
blob: 97daca6cf4758e0cca04e84816333274c8fc3405 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
""" Gerrit event stream interface.

Class to listen to the Gerrit event stream and dispatch events.

"""

import json

from events import PatchsetCreatedEvent, \
    RefUpdatedEvent, ChangeMergedEvent, CommentAddedEvent, \
    ChangeAbandonedEvent, ChangeRestoredEvent, \
    DraftPublishedEvent


# Event types
CHANGE_MERGED = "change-merged"
PATCHSET_CREATED = "patchset-created"
DRAFT_PUBLISHED = "draft-published"
COMMENT_ADDED = "comment-added"
CHANGE_ABANDONED = "change-abandoned"
CHANGE_RESTORED = "change-restored"
REF_UPDATED = "ref-updated"


class GerritStreamError(Exception):
    ''' GerritStreamError is raised when an error occurs while
    reading the Gerrit events stream.
    '''


class GerritStream(object):
    ''' Gerrit stream handler.
    '''

    # Map the event types to class names.
    _event_dict = {CHANGE_MERGED: "ChangeMergedEvent",
                   PATCHSET_CREATED: "PatchsetCreatedEvent",
                   DRAFT_PUBLISHED: "DraftPublishedEvent",
                   COMMENT_ADDED: "CommentAddedEvent",
                   CHANGE_ABANDONED: "ChangeAbandonedEvent",
                   CHANGE_RESTORED: "ChangeRestoredEvent",
                   REF_UPDATED: "RefUpdatedEvent"}

    def __init__(self):
        self.listeners = []

    def attach(self, listener):
        ''' Attach the `listener` to the list of listeners.
        Raise GerritStreamError if the listener does not match the
        expected signature, or if its event handler is not callable.
        '''
        if not hasattr(listener, "on_gerrit_event"):
            raise GerritStreamError("Listener must have `on_gerrit_event` "
                                    "event handler method")
        if not callable(listener.on_gerrit_event):
            raise GerritStreamError("`on_gerrit_event` must be callable")
        if not listener.on_gerrit_event.func_code.co_argcount == 2:
            raise GerritStreamError("`on_gerrit_event` must take 1 arg")
        if not listener in self.listeners:
            self.listeners.append(listener)

    def detach(self, listener):
        ''' Remove the `listener` from the list of listeners.
        '''
        if listener in self.listeners:
            try:
                self.listeners.remove(listener)
            except ValueError:
                pass

    def _get_event(self, json_data):
        ''' Create a new 'GerritEvent' from the JSON object
        described in `json_data`.
        Return an instance of one of the GerritEvent subclasses.
        Raise GerritStreamError if any error occurs.
        '''
        event_type = json_data["type"]
        if event_type in self._event_dict:
            classname = self._event_dict[event_type]
            try:
                return globals()[classname](json_data)
            except KeyError, e:
                raise GerritStreamError("Error creating event: %s" % e)

        raise GerritStreamError("Unexpected event type `%s`" % event_type)

    def _dispatch_event(self, event):
        ''' Dispatch the `event` to the listeners.
        '''
        for listener in self.listeners:
            listener.on_gerrit_event(event)

    def stream(self, inputstream):
        ''' Listen to the `inputstream` and handle JSON objects.
        '''
        try:
            done = 0
            while not done:
                line = inputstream.readline()
                if line:
                    data = json.loads(line)
                    self._dispatch_event(self._get_event(data))
                else:
                    break
        except IOError, e:
            raise GerritStreamError("Error reading event stream: %s" % e)
        except ValueError, e:
            raise GerritStreamError("Invalid JSON data in event stream: %s" % e)