summaryrefslogtreecommitdiff
path: root/lorrycontroller/gitano.py
diff options
context:
space:
mode:
Diffstat (limited to 'lorrycontroller/gitano.py')
-rw-r--r--lorrycontroller/gitano.py130
1 files changed, 130 insertions, 0 deletions
diff --git a/lorrycontroller/gitano.py b/lorrycontroller/gitano.py
new file mode 100644
index 0000000..b2c9123
--- /dev/null
+++ b/lorrycontroller/gitano.py
@@ -0,0 +1,130 @@
+# Copyright (C) 2014 Codethink Limited
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+
+import collections
+import logging
+import re
+import urllib2
+import urlparse
+
+import cliapp
+
+import lorrycontroller
+
+
+class GitanoCommandFailure(Exception):
+
+ def __init__(self, trovehost, command, stderr):
+ Exception.__init__(
+ self,
+ 'Failed to run "%s" on Gitano on %s\n%s' %
+ (command, trovehost, stderr))
+
+
+class GitanoCommand(object):
+
+ '''Run a Gitano command on a Trove.'''
+
+ def __init__(self, trovehost, protocol, username, password):
+ self.trovehost = trovehost
+ self.protocol = protocol
+ self.username = username
+ self.password = password
+
+ if protocol == 'ssh':
+ self._command = self._ssh_command
+ elif protocol in ('http', 'https'):
+ self._command = self._http_command
+ else:
+ raise GitanoCommandFailure(
+ self.trovehost, '__init__', 'unknown protocol %s' % protocol)
+
+ def whoami(self):
+ return self._command(['whoami'])
+
+ def create(self, repo_path):
+ self._command(['create', repo_path])
+
+ def get_gitano_config(self, repo_path):
+ stdout = self._command(['config', repo_path, 'show'])
+
+ # "config REPO show" outputs a sequence of lines of the form "key: value".
+ # Extract those into a collections.defaultdict.
+
+ result = collections.defaultdict(str)
+ for line in stdout.splitlines():
+ m = re.match(r'^([^:])+:\s*(.*)$', line)
+ if m:
+ result[m.group(0)] = m.group(1).strip()
+
+ return result
+
+ def set_gitano_config(self, path, key, value):
+ self._command(['config', path, 'set', key, value])
+
+ def ls(self):
+ return self._command(['ls'])
+
+ def _ssh_command(self, gitano_args):
+ quoted_args = [cliapp.shell_quote(x) for x in gitano_args]
+
+ base_argv = [
+ 'ssh',
+ '-oStrictHostKeyChecking=no',
+ '-oBatchMode=yes',
+ 'git@%s' % self.trovehost,
+ ]
+
+ exit, stdout, stderr = cliapp.runcmd_unchecked(
+ base_argv + quoted_args)
+
+ if exit != 0:
+ logging.error(
+ 'Failed to run "%s" for %s:\n%s',
+ self.trovehost, stdout + stderr)
+ raise GitanoCommandFailure(
+ self.trovehost,
+ ' '.join(gitano_args),
+ stdout + stderr)
+
+ return stdout
+
+ def _http_command(self, gitano_args):
+ quoted_args = urllib2.quote(' '.join(gitano_args))
+ url = urlparse.urlunsplit((
+ self.protocol,
+ self.trovehost,
+ '/gitano-command.cgi',
+ 'cmd=%s' % quoted_args,
+ ''))
+ logging.debug('url=%r', url)
+
+ try:
+ request = urllib2.Request(url, None, {})
+ logging.debug('request=%r', request.get_full_url())
+ if self.username and self.password:
+ password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
+ password_mgr.add_password(None, url, self.username, self.password)
+ auth_handler = urllib2.HTTPBasicAuthHandler(password_mgr)
+ opener = urllib2.build_opener(auth_handler)
+ response = opener.open(url)
+ else:
+ response = urllib2.urlopen(request)
+ except urllib2.URLError as e:
+ raise GitanoCommandFailure(
+ self.trovehost, ' '.join(gitano_args), str(e))
+
+ return response.read()