diff rhodecode/bin/rhodecode_api.py @ 2379:7ac09514a178 beta

created rhodecode-api binary script for working with api via cli - created docs - moved the backup script to bin folder
author Marcin Kuzminski <marcin@python-works.com>
date Sun, 03 Jun 2012 20:35:13 +0200
parents
children e487d2a6aa38
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/bin/rhodecode_api.py	Sun Jun 03 20:35:13 2012 +0200
@@ -0,0 +1,216 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.bin.backup_manager
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Api CLI client for RhodeCode
+
+    :created_on: Jun 3, 2012
+    :author: marcink
+    :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
+    :license: GPLv3, see COPYING for more details.
+"""
+# 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, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+from __future__ import with_statement
+import os
+import sys
+import random
+import urllib2
+import pprint
+import argparse
+
+try:
+    from rhodecode.lib.ext_json import json
+except ImportError:
+    try:
+        import simplejson as json
+    except ImportError:
+        import json
+
+
+CONFIG_NAME = '.rhodecode'
+
+
+class RcConf(object):
+    """
+    RhodeCode config for API
+
+    conf = RcConf()
+    conf['key']
+
+    """
+
+    def __init__(self, autoload=True, autocreate=False, config=None):
+        self._conf_name = CONFIG_NAME
+        self._conf = {}
+        if autocreate:
+            self.make_config(config)
+        if autoload:
+            self._conf = self.load_config()
+
+    def __getitem__(self, key):
+        return self._conf[key]
+
+    def __nonzero__(self):
+        if self._conf:
+            return True
+        return False
+
+    def __eq__(self):
+        return self._conf.__eq__()
+
+    def __repr__(self):
+        return 'RcConf<%s>' % self._conf.__repr__()
+
+    def make_config(self, config):
+        """
+        Saves given config as a JSON dump in the _conf_name location
+
+        :param config:
+        :type config:
+        """
+        with open(self._conf_name, 'wb') as f:
+            json.dump(config, f, indent=4)
+            sys.stdout.write('Updated conf\n')
+
+    def update_config(self, new_config):
+        """
+        Reads the JSON config updates it's values with new_config and
+        saves it back as JSON dump
+
+        :param new_config:
+        """
+        config = {}
+        try:
+            with open(self._conf_name, 'rb') as conf:
+                config = json.load(conf)
+        except IOError, e:
+            sys.stderr.write(str(e) + '\n')
+
+        config.update(new_config)
+        self.make_config(config)
+
+    def load_config(self):
+        """
+        Loads config from file and returns loaded JSON object
+        """
+        try:
+            with open(self._conf_name, 'rb') as conf:
+                return  json.load(conf)
+        except IOError, e:
+            #sys.stderr.write(str(e) + '\n')
+            pass
+
+
+def api_call(apikey, apihost, method=None, **kw):
+    """
+    Api_call wrapper for RhodeCode
+
+    :param apikey:
+    :param apihost:
+    :param method:
+    """
+    def _build_data(random_id):
+        """
+        Builds API data with given random ID
+
+        :param random_id:
+        :type random_id:
+        """
+        return {
+            "id": random_id,
+            "api_key": apikey,
+            "method": method,
+            "args": kw
+        }
+
+    if not method:
+        raise Exception('please specify method name !')
+    id_ = random.randrange(1, 200)
+    req = urllib2.Request('%s/_admin/api' % apihost,
+                      data=json.dumps(_build_data(id_)),
+                      headers={'content-type': 'text/plain'})
+    print 'calling %s to %s' % (req.get_data(), apihost)
+    ret = urllib2.urlopen(req)
+    json_data = json.loads(ret.read())
+    id_ret = json_data['id']
+    _formatted_json = pprint.pformat(json_data)
+    if id_ret == id_:
+        print 'rhodecode said:\n%s' % (_formatted_json)
+    else:
+        raise Exception('something went wrong. '
+                        'ID mismatch got %s, expected %s | %s' % (
+                                            id_ret, id_, _formatted_json))
+
+
+def argparser(argv):
+    usage = ("rhodecode_api [-h] [--apikey APIKEY] [--apihost APIHOST] "
+             "_create_config or METHOD <key:val> <key2:val> ...")
+
+    parser = argparse.ArgumentParser(description='RhodeCode API cli',
+                                     usage=usage)
+
+    ## config
+    group = parser.add_argument_group('config')
+    group.add_argument('--apikey', help='api access key')
+    group.add_argument('--apihost', help='api host')
+
+    group = parser.add_argument_group('API')
+    group.add_argument('method', metavar='METHOD', type=str,
+            help='API method name to call followed by key:value attributes',
+    )
+
+    args, other = parser.parse_known_args()
+    return parser, args, other
+
+
+def main(argv=None):
+    """
+    Main execution function for cli
+
+    :param argv:
+    :type argv:
+    """
+    if argv is None:
+        argv = sys.argv
+
+    conf = None
+    parser, args, other = argparser(argv)
+
+    api_credentials_given = (args.apikey and args.apihost)
+    if args.method == '_create_config':
+        if not api_credentials_given:
+            raise parser.error('_create_config requires --apikey and --apihost')
+        conf = RcConf(autocreate=True, config={'apikey': args.apikey,
+                                               'apihost': args.apihost})
+        sys.stdout.write('Create new config in %s\n' % CONFIG_NAME)
+
+    if not conf:
+        conf = RcConf(autoload=True)
+        if not conf:
+            if not api_credentials_given:
+                parser.error('Could not find config file and missing '
+                             '--apikey or --apihost in params')
+
+    apikey = args.apikey or conf['apikey']
+    host = args.apihost or conf['apihost']
+    method = args.method
+    margs = dict(map(lambda s: s.split(':', 1), other))
+
+    api_call(apikey, host, method, **margs)
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))