diff options
Diffstat (limited to 'pygerrit/client.py')
-rw-r--r-- | pygerrit/client.py | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/pygerrit/client.py b/pygerrit/client.py new file mode 100644 index 0000000..4095914 --- /dev/null +++ b/pygerrit/client.py @@ -0,0 +1,136 @@ +# The MIT License +# +# Copyright 2012 Sony Mobile Communications. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +""" Gerrit client interface. """ + +from json import JSONDecoder +from Queue import Queue, Empty, Full + +from . import escape_string +from .error import GerritError +from .events import GerritEventFactory +from .models import Change +from .ssh import GerritSSHClient +from .stream import GerritStream + + +class GerritClient(object): + + """ Gerrit client interface. """ + + def __init__(self, host, username=None, port=None): + self._factory = GerritEventFactory() + self._events = Queue() + self._stream = None + self._ssh_client = GerritSSHClient(host, username=username, port=port) + + def gerrit_version(self): + """ Return the version of Gerrit that is connected to. """ + return self._ssh_client.get_remote_version() + + def gerrit_info(self): + """ Return the username, and version of Gerrit that is connected to. """ + return self._ssh_client.get_remote_info() + + def run_command(self, command): + """ Run the command. Return the result. """ + if not isinstance(command, basestring): + raise ValueError("command must be a string") + return self._ssh_client.run_gerrit_command(command) + + def query(self, term): + """ Run `gerrit query` with the given `term`. + + Return a list of results as `Change` objects. + + Raise `ValueError` if `term` is not a string. + + """ + results = [] + command = ["query", "--current-patch-set", "--all-approvals", + "--format JSON", "--commit-message"] + + if not isinstance(term, basestring): + raise ValueError("term must be a string") + + command.append(escape_string(term)) + result = self._ssh_client.run_gerrit_command(" ".join(command)) + decoder = JSONDecoder() + for line in result.stdout.read().splitlines(): + # Gerrit's response to the query command contains one or more + # lines of JSON-encoded strings. The last one is a status + # dictionary containing the key "type" whose value indicates + # whether or not the operation was successful. + # According to http://goo.gl/h13HD it should be safe to use the + # presence of the "type" key to determine whether the dictionary + # represents a change or if it's the query status indicator. + try: + data = decoder.decode(line) + except ValueError as err: + raise GerritError("Query returned invalid data: %s", err) + if "type" in data and data["type"] == "error": + raise GerritError("Query error: %s" % data["message"]) + elif "project" in data: + results.append(Change(data)) + return results + + def start_event_stream(self): + """ Start streaming events from `gerrit stream-events`. """ + if not self._stream: + self._stream = GerritStream(self, ssh_client=self._ssh_client) + self._stream.start() + + def stop_event_stream(self): + """ Stop streaming events from `gerrit stream-events`.""" + if self._stream: + self._stream.stop() + self._stream.join() + self._stream = None + with self._events.mutex: + self._events.queue.clear() + + def get_event(self, block=True, timeout=None): + """ Get the next event from the queue. + + Return a `GerritEvent` instance, or None if: + - `block` is False and there is no event available in the queue, or + - `block` is True and no event is available within the time + specified by `timeout`. + + """ + try: + return self._events.get(block, timeout) + except Empty: + return None + + def put_event(self, data): + """ Create event from `data` and add it to the queue. + + Raise GerritError if the queue is full, or the factory could not + create the event. + + """ + try: + event = self._factory.create(data) + self._events.put(event) + except Full: + raise GerritError("Unable to add event: queue is full") |