diff --git a/rhodecode/bin/base.py b/rhodecode/bin/base.py new file mode 100644 --- /dev/null +++ b/rhodecode/bin/base.py @@ -0,0 +1,148 @@ +""" +Base utils for shell scripts +""" +import os +import sys +import random +import urllib2 +import pprint + +try: + from rhodecode.lib.ext_json import json +except ImportError: + try: + import simplejson as json + except ImportError: + import json + +CONFIG_NAME = '.rhodecode' +FORMAT_PRETTY = 'pretty' +FORMAT_JSON = 'json' + + +def api_call(apikey, apihost, format, method=None, **kw): + """ + Api_call wrapper for RhodeCode + + :param apikey: + :param apihost: + :param format: formatting, pretty means prints and pprint of json + json returns unparsed json + :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, 9999) + req = urllib2.Request('%s/_admin/api' % apihost, + data=json.dumps(_build_data(id_)), + headers={'content-type': 'text/plain'}) + if format == FORMAT_PRETTY: + sys.stdout.write('calling %s to %s \n' % (req.get_data(), apihost)) + ret = urllib2.urlopen(req) + raw_json = ret.read() + json_data = json.loads(raw_json) + id_ret = json_data['id'] + _formatted_json = pprint.pformat(json_data) + if id_ret == id_: + if format == FORMAT_JSON: + sys.stdout.write(str(raw_json)) + else: + sys.stdout.write('rhodecode returned:\n%s\n' % (_formatted_json)) + + else: + raise Exception('something went wrong. ' + 'ID mismatch got %s, expected %s | %s' % ( + id_ret, id_, _formatted_json)) + + +class RcConf(object): + """ + RhodeCode config for API + + conf = RcConf() + conf['key'] + + """ + + def __init__(self, config_location=None, autoload=True, autocreate=False, + config=None): + self._conf_name = CONFIG_NAME if not config_location else config_location + 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: + """ + update = False + if os.path.exists(self._conf_name): + update = True + with open(self._conf_name, 'wb') as f: + json.dump(config, f, indent=4) + + if update: + sys.stdout.write('Updated config in %s\n' % self._conf_name) + else: + sys.stdout.write('Created new config in %s\n' % self._conf_name) + + 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 diff --git a/rhodecode/bin/rhodecode_api.py b/rhodecode/bin/rhodecode_api.py --- a/rhodecode/bin/rhodecode_api.py +++ b/rhodecode/bin/rhodecode_api.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - rhodecode.bin.backup_manager - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + rhodecode.bin.api + ~~~~~~~~~~~~~~~~~ Api CLI client for RhodeCode @@ -24,160 +24,18 @@ # along with this program. If not, see . 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' -FORMAT_PRETTY = 'pretty' -FORMAT_JSON = 'json' - - -class RcConf(object): - """ - RhodeCode config for API - - conf = RcConf() - conf['key'] - - """ - - def __init__(self, config_location=None, autoload=True, autocreate=False, - config=None): - self._conf_name = CONFIG_NAME if not config_location else config_location - 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: - """ - update = False - if os.path.exists(self._conf_name): - update = True - with open(self._conf_name, 'wb') as f: - json.dump(config, f, indent=4) - - if update: - sys.stdout.write('Updated config in %s\n' % self._conf_name) - else: - sys.stdout.write('Created new config in %s\n' % self._conf_name) - - 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, format, method=None, **kw): - """ - Api_call wrapper for RhodeCode - - :param apikey: - :param apihost: - :param format: formatting, pretty means prints and pprint of json - json returns unparsed json - :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, 9999) - req = urllib2.Request('%s/_admin/api' % apihost, - data=json.dumps(_build_data(id_)), - headers={'content-type': 'text/plain'}) - if format == FORMAT_PRETTY: - sys.stdout.write('calling %s to %s \n' % (req.get_data(), apihost)) - ret = urllib2.urlopen(req) - raw_json = ret.read() - json_data = json.loads(raw_json) - id_ret = json_data['id'] - _formatted_json = pprint.pformat(json_data) - if id_ret == id_: - if format == FORMAT_JSON: - sys.stdout.write(str(raw_json)) - else: - sys.stdout.write('rhodecode returned:\n%s\n' % (_formatted_json)) - - else: - raise Exception('something went wrong. ' - 'ID mismatch got %s, expected %s | %s' % ( - id_ret, id_, _formatted_json)) +from rhodecode.bin.base import api_call, RcConf, FORMAT_JSON, FORMAT_PRETTY def argparser(argv): usage = ( - "rhodecode_api [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] " - " [--config=CONFIG] " - "_create_config or METHOD ..." + "rhodecode-api [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] " + "[--config=CONFIG] [--save-config] " + "METHOD ...\n" + "Create config file: rhodecode-gist --apikey= --apihost=http://rhodecode.server --save-config" ) parser = argparse.ArgumentParser(description='RhodeCode API cli', @@ -188,9 +46,10 @@ def argparser(argv): group.add_argument('--apikey', help='api access key') group.add_argument('--apihost', help='api host') group.add_argument('--config', help='config file') + group.add_argument('--save-config', action='store_true', help='save the given config into a file') group = parser.add_argument_group('API') - group.add_argument('method', metavar='METHOD', type=str, + group.add_argument('method', metavar='METHOD', nargs='?', type=str, default=None, help='API method name to call followed by key:value attributes', ) group.add_argument('--format', dest='format', type=str, @@ -216,12 +75,13 @@ def main(argv=None): parser, args, other = argparser(argv) api_credentials_given = (args.apikey and args.apihost) - if args.method == '_create_config': + if args.save_config: if not api_credentials_given: - raise parser.error('_create_config requires --apikey and --apihost') + raise parser.error('--save-config requires --apikey and --apihost') conf = RcConf(config_location=args.config, autocreate=True, config={'apikey': args.apikey, 'apihost': args.apihost}) + sys.exit() if not conf: conf = RcConf(config_location=args.config, autoload=True) @@ -233,8 +93,6 @@ def main(argv=None): apikey = args.apikey or conf['apikey'] host = args.apihost or conf['apihost'] method = args.method - if method == '_create_config': - sys.exit() try: margs = dict(map(lambda s: s.split(':', 1), other))