changeset 4189:9793473d74be kallithea-2.2.5-rebrand

Rename helper tools (and fix inconsistent naming)
author Bradley M. Kuhn <bkuhn@sfconservancy.org>
date Wed, 02 Jul 2014 19:04:39 -0400
parents 6c0215b29750
children 99ad9d0af1a3
files docs/api/api.rst kallithea/bin/kallithea_api.py kallithea/bin/kallithea_backup.py kallithea/bin/kallithea_config.py kallithea/bin/kallithea_gist.py kallithea/bin/ldap_sync.py kallithea/bin/rhodecode_api.py kallithea/bin/rhodecode_backup.py kallithea/bin/rhodecode_config.py kallithea/bin/rhodecode_gist.py kallithea/tests/scripts/create_rc.sh setup.py
diffstat 12 files changed, 589 insertions(+), 589 deletions(-) [+]
line wrap: on
line diff
--- a/docs/api/api.rst	Wed Jul 02 19:04:33 2014 -0400
+++ b/docs/api/api.rst	Wed Jul 02 19:04:39 2014 -0400
@@ -79,12 +79,12 @@
 ++++++++++
 
 From version 1.4 RhodeCode adds a script that allows to easily
-communicate with API. After installing RhodeCode a `rhodecode-api` script
+communicate with API. After installing RhodeCode a `kallithea-api` script
 will be available.
 
 To get started quickly simply run::
 
-  rhodecode-api _create_config --apikey=<youapikey> --apihost=<your.kallithea.server>
+  kallithea-api _create_config --apikey=<youapikey> --apihost=<your.kallithea.server>
 
 This will create a file named .config in the directory you executed it storing
 json config file with credentials. You can skip this step and always provide
@@ -93,7 +93,7 @@
 
 after that simply run any api command for example get_repo::
 
- rhodecode-api get_repo
+ kallithea-api get_repo
 
  calling {"api_key": "<apikey>", "id": 75, "args": {}, "method": "get_repo"} to http://127.0.0.1:5000
  rhodecode said:
@@ -105,7 +105,7 @@
 
 Let's try again now giving the repoid as parameters::
 
-    rhodecode-api get_repo repoid:rhodecode
+    kallithea-api get_repo repoid:rhodecode
 
     calling {"api_key": "<apikey>", "id": 39, "args": {"repoid": "rhodecode"}, "method": "get_repo"} to http://127.0.0.1:5000
     rhodecode said:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kallithea/bin/kallithea_api.py	Wed Jul 02 19:04:39 2014 -0400
@@ -0,0 +1,124 @@
+# -*- coding: utf-8 -*-
+# 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/>.
+"""
+kallithea.bin.api
+~~~~~~~~~~~~~~~~~
+
+Api CLI client for RhodeCode
+
+:created_on: Jun 3, 2012
+:author: marcink
+:copyright: (c) 2013 RhodeCode GmbH.
+:license: GPLv3, see LICENSE for more details.
+"""
+
+from __future__ import with_statement
+import sys
+import argparse
+
+from kallithea.bin.base import json, api_call, RcConf, FORMAT_JSON, FORMAT_PRETTY
+
+
+def argparser(argv):
+    usage = (
+      "kallithea-api [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
+      "[--config=CONFIG] [--save-config] "
+      "METHOD <key:val> <key2:val> ...\n"
+      "Create config file: kallithea-api --apikey=<key> --apihost=http://your.kallithea.server --save-config"
+    )
+
+    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.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', nargs='?', type=str, default=None,
+            help='API method name to call followed by key:value attributes',
+    )
+    group.add_argument('--format', dest='format', type=str,
+            help='output format default: `%s` can '
+                 'be also `%s`' % (FORMAT_PRETTY, FORMAT_JSON),
+            default=FORMAT_PRETTY
+    )
+    args, other = parser.parse_known_args()
+    return parser, args, other
+
+
+def main(argv=None):
+    """
+    Main execution function for cli
+
+    :param 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.save_config:
+        if not api_credentials_given:
+            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)
+        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']
+    apihost = args.apihost or conf['apihost']
+    method = args.method
+
+    # if we don't have method here it's an error
+    if not method:
+        parser.error('Please specify method name')
+
+    try:
+        margs = dict(map(lambda s: s.split(':', 1), other))
+    except Exception:
+        sys.stderr.write('Error parsing arguments \n')
+        sys.exit()
+    if args.format == FORMAT_PRETTY:
+        print 'Calling method %s => %s' % (method, apihost)
+
+    json_resp = api_call(apikey, apihost, method, **margs)
+    error_prefix = ''
+    if json_resp['error']:
+        error_prefix = 'ERROR:'
+        json_data = json_resp['error']
+    else:
+        json_data = json_resp['result']
+    if args.format == FORMAT_JSON:
+        print json.dumps(json_data)
+    elif args.format == FORMAT_PRETTY:
+        print 'Server response \n%s%s' % (
+            error_prefix, json.dumps(json_data, indent=4, sort_keys=True)
+        )
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kallithea/bin/kallithea_backup.py	Wed Jul 02 19:04:39 2014 -0400
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+# 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/>.
+"""
+kallithea.bin.backup_manager
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Repositories backup manager, it allows to backups all
+repositories and send it to backup server using RSA key via ssh.
+
+:created_on: Feb 28, 2010
+:author: marcink
+:copyright: (c) 2013 RhodeCode GmbH.
+:license: GPLv3, see LICENSE for more details.
+"""
+
+import os
+import sys
+
+import logging
+import tarfile
+import datetime
+import subprocess
+
+logging.basicConfig(level=logging.DEBUG,
+                    format="%(asctime)s %(levelname)-5.5s %(message)s")
+
+
+class BackupManager(object):
+    def __init__(self, repos_location, rsa_key, backup_server):
+        today = datetime.datetime.now().weekday() + 1
+        self.backup_file_name = "repos.%s.tar.gz" % today
+
+        self.id_rsa_path = self.get_id_rsa(rsa_key)
+        self.repos_path = self.get_repos_path(repos_location)
+        self.backup_server = backup_server
+
+        self.backup_file_path = '/tmp'
+
+        logging.info('starting backup for %s', self.repos_path)
+        logging.info('backup target %s', self.backup_file_path)
+
+    def get_id_rsa(self, rsa_key):
+        if not os.path.isfile(rsa_key):
+            logging.error('Could not load id_rsa key file in %s', rsa_key)
+            sys.exit()
+        return rsa_key
+
+    def get_repos_path(self, path):
+        if not os.path.isdir(path):
+            logging.error('Wrong location for repositories in %s', path)
+            sys.exit()
+        return path
+
+    def backup_repos(self):
+        bckp_file = os.path.join(self.backup_file_path, self.backup_file_name)
+        tar = tarfile.open(bckp_file, "w:gz")
+
+        for dir_name in os.listdir(self.repos_path):
+            logging.info('backing up %s', dir_name)
+            tar.add(os.path.join(self.repos_path, dir_name), dir_name)
+        tar.close()
+        logging.info('finished backup of mercurial repositories')
+
+    def transfer_files(self):
+        params = {
+                  'id_rsa_key': self.id_rsa_path,
+                  'backup_file': os.path.join(self.backup_file_path,
+                                             self.backup_file_name),
+                  'backup_server': self.backup_server
+                  }
+        cmd = ['scp', '-l', '40000', '-i', '%(id_rsa_key)s' % params,
+               '%(backup_file)s' % params,
+               '%(backup_server)s' % params]
+
+        subprocess.call(cmd)
+        logging.info('Transfered file %s to %s', self.backup_file_name, cmd[4])
+
+    def rm_file(self):
+        logging.info('Removing file %s', self.backup_file_name)
+        os.remove(os.path.join(self.backup_file_path, self.backup_file_name))
+
+if __name__ == "__main__":
+
+    repo_location = '/home/repo_path'
+    backup_server = 'root@192.168.1.100:/backups/mercurial'
+    rsa_key = '/home/id_rsa'
+
+    B_MANAGER = BackupManager(repo_location, rsa_key, backup_server)
+    B_MANAGER.backup_repos()
+    B_MANAGER.transfer_files()
+    B_MANAGER.rm_file()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kallithea/bin/kallithea_config.py	Wed Jul 02 19:04:39 2014 -0400
@@ -0,0 +1,160 @@
+# -*- coding: utf-8 -*-
+# 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/>.
+"""
+kallithea.bin.kallithea_config
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+configuration generator for RhodeCode
+
+:created_on: Jun 18, 2013
+:author: marcink
+:copyright: (c) 2013 RhodeCode GmbH.
+:license: GPLv3, see LICENSE for more details.
+"""
+
+
+from __future__ import with_statement
+import os
+import sys
+import uuid
+import argparse
+from mako.template import Template
+TMPL = 'template.ini.mako'
+here = os.path.dirname(os.path.abspath(__file__))
+
+def argparser(argv):
+    usage = (
+      "kallithea-config [-h] [--filename=FILENAME] [--template=TEMPLATE] \n"
+      "VARS optional specify extra template variable that will be available in "
+      "template. Use comma separated key=val format eg.\n"
+      "key1=val1,port=5000,host=127.0.0.1,elements='a\,b\,c'\n"
+    )
+
+    parser = argparse.ArgumentParser(
+        description='RhodeCode CONFIG generator with variable replacement',
+        usage=usage
+    )
+
+    ## config
+    group = parser.add_argument_group('CONFIG')
+    group.add_argument('--filename', help='Output ini filename.')
+    group.add_argument('--template', help='Mako template file to use instead of '
+                                          'the default builtin template')
+    group.add_argument('--raw', help='Store given mako template as raw without '
+                                     'parsing. Use this to create custom template '
+                                     'initially', action='store_true')
+    group.add_argument('--show-defaults', help='Show all default variables for '
+                                               'builtin template', action='store_true')
+    args, other = parser.parse_known_args()
+    return parser, args, other
+
+
+def _escape_split(text, sep):
+    """
+    Allows for escaping of the separator: e.g. arg='foo\, bar'
+
+    It should be noted that the way bash et. al. do command line parsing, those
+    single quotes are required. a shameless ripoff from fabric project.
+
+    """
+    escaped_sep = r'\%s' % sep
+
+    if escaped_sep not in text:
+        return text.split(sep)
+
+    before, _, after = text.partition(escaped_sep)
+    startlist = before.split(sep)  # a regular split is fine here
+    unfinished = startlist[-1]
+    startlist = startlist[:-1]
+
+    # recurse because there may be more escaped separators
+    endlist = _escape_split(after, sep)
+
+    # finish building the escaped value. we use endlist[0] becaue the first
+    # part of the string sent in recursion is the rest of the escaped value.
+    unfinished += sep + endlist[0]
+
+    return startlist + [unfinished] + endlist[1:]  # put together all the parts
+
+def _run(argv):
+    parser, args, other = argparser(argv)
+    if not len(sys.argv) > 1:
+        print parser.print_help()
+        sys.exit(0)
+    # defaults that can be overwritten by arguments
+    tmpl_stored_args = {
+        'http_server': 'waitress',
+        'lang': 'en',
+        'database_engine': 'sqlite',
+        'host': '127.0.0.1',
+        'port': 5000,
+        'error_aggregation_service': None,
+    }
+    if other:
+        # parse arguments, we assume only first is correct
+        kwargs = {}
+        for el in _escape_split(other[0], ','):
+            kv = _escape_split(el, '=')
+            if len(kv) == 2:
+                k, v = kv
+                kwargs[k] = v
+        # update our template stored args
+        tmpl_stored_args.update(kwargs)
+
+    # use default that cannot be replaced
+    tmpl_stored_args.update({
+        'uuid': lambda: uuid.uuid4().hex,
+        'here': os.path.abspath(os.curdir),
+    })
+    if args.show_defaults:
+        for k,v in tmpl_stored_args.iteritems():
+            print '%s=%s' % (k, v)
+        sys.exit(0)
+    try:
+        # built in template
+        tmpl_file = os.path.join(here, TMPL)
+        if args.template:
+            tmpl_file = args.template
+
+        with open(tmpl_file, 'rb') as f:
+            tmpl_data = f.read()
+            if args.raw:
+                tmpl = tmpl_data
+            else:
+                tmpl = Template(tmpl_data).render(**tmpl_stored_args)
+        with open(args.filename, 'wb') as f:
+            f.write(tmpl)
+        print 'Wrote new config file in %s' % (os.path.abspath(args.filename))
+
+    except Exception:
+        from mako import exceptions
+        print exceptions.text_error_template().render()
+
+def main(argv=None):
+    """
+    Main execution function for cli
+
+    :param argv:
+    """
+    if argv is None:
+        argv = sys.argv
+
+    try:
+        return _run(argv)
+    except Exception:
+        raise
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kallithea/bin/kallithea_gist.py	Wed Jul 02 19:04:39 2014 -0400
@@ -0,0 +1,171 @@
+# -*- coding: utf-8 -*-
+# 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/>.
+"""
+kallithea.bin.kallithea_gist
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Gist CLI client for RhodeCode
+
+:created_on: May 9, 2013
+:author: marcink
+:copyright: (c) 2013 RhodeCode GmbH.
+:license: GPLv3, see LICENSE for more details.
+"""
+
+from __future__ import with_statement
+import os
+import sys
+import stat
+import argparse
+import fileinput
+
+from kallithea.bin.base import json, api_call, RcConf, FORMAT_JSON, FORMAT_PRETTY
+
+
+def argparser(argv):
+    usage = (
+      "kallithea-gist [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
+      "[--config=CONFIG] [--save-config] [GIST OPTIONS] "
+      "[filename or stdin use - for terminal stdin ]\n"
+      "Create config file: kallithea-gist --apikey=<key> --apihost=http://your.kallithea.server --save-config"
+    )
+
+    parser = argparse.ArgumentParser(description='RhodeCode Gist 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.add_argument('--config', help='config file path DEFAULT: ~/.config/kallithea')
+    group.add_argument('--save-config', action='store_true',
+                       help='save the given config into a file')
+
+    group = parser.add_argument_group('GIST')
+    group.add_argument('-p', '--private', action='store_true',
+                       help='create private Gist')
+    group.add_argument('-f', '--filename',
+                       help='set uploaded gist filename, '
+                            'also defines syntax highlighting')
+    group.add_argument('-d', '--description', help='Gist description')
+    group.add_argument('-l', '--lifetime', metavar='MINUTES',
+                       help='gist lifetime in minutes, -1 (DEFAULT) is forever')
+    group.add_argument('--format', dest='format', type=str,
+                       help='output format DEFAULT: `%s` can '
+                       'be also `%s`' % (FORMAT_PRETTY, FORMAT_JSON),
+            default=FORMAT_PRETTY
+    )
+    args, other = parser.parse_known_args()
+    return parser, args, other
+
+
+def _run(argv):
+    conf = None
+    parser, args, other = argparser(argv)
+
+    api_credentials_given = (args.apikey and args.apihost)
+    if args.save_config:
+        if not api_credentials_given:
+            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)
+        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']
+    DEFAULT_FILENAME = 'gistfile1.txt'
+    if other:
+        # skip multifiles for now
+        filename = other[0]
+        if filename == '-':
+            filename = DEFAULT_FILENAME
+            gist_content = ''
+            for line in fileinput.input('-'):
+                gist_content += line
+        else:
+            with open(filename, 'rb') as f:
+                gist_content = f.read()
+
+    else:
+        filename = DEFAULT_FILENAME
+        gist_content = None
+        # little bit hacky but cross platform check where the
+        # stdin comes from we skip the terminal case it can be handled by '-'
+        mode = os.fstat(0).st_mode
+        if stat.S_ISFIFO(mode):
+            # "stdin is piped"
+            gist_content = sys.stdin.read()
+        elif stat.S_ISREG(mode):
+            # "stdin is redirected"
+            gist_content = sys.stdin.read()
+        else:
+            # "stdin is terminal"
+            pass
+
+    # make sure we don't upload binary stuff
+    if gist_content and '\0' in gist_content:
+        raise Exception('Error: binary files upload is not possible')
+
+    filename = os.path.basename(args.filename or filename)
+    if gist_content:
+        files = {
+            filename: {
+                'content': gist_content,
+                'lexer': None
+            }
+        }
+
+        margs = dict(
+            lifetime=args.lifetime,
+            description=args.description,
+            gist_type='private' if args.private else 'public',
+            files=files
+        )
+
+        json_data = api_call(apikey, host, 'create_gist', **margs)['result']
+        if args.format == FORMAT_JSON:
+            print json.dumps(json_data)
+        elif args.format == FORMAT_PRETTY:
+            print json_data
+            print 'Created %s gist %s' % (json_data['gist']['type'],
+                                          json_data['gist']['url'])
+    return 0
+
+
+def main(argv=None):
+    """
+    Main execution function for cli
+
+    :param argv:
+    """
+    if argv is None:
+        argv = sys.argv
+
+    try:
+        return _run(argv)
+    except Exception, e:
+        print e
+        return 1
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
--- a/kallithea/bin/ldap_sync.py	Wed Jul 02 19:04:33 2014 -0400
+++ b/kallithea/bin/ldap_sync.py	Wed Jul 02 19:04:39 2014 -0400
@@ -45,7 +45,7 @@
     """ Request and response don't have the same UUID. """
 
 
-class RhodecodeResponseError(Exception):
+class ResponseError(Exception):
     """ Response has an error, something went wrong with request execution. """
 
 
@@ -57,7 +57,7 @@
     """ User is not a member of the target group. """
 
 
-class RhodecodeAPI(object):
+class API(object):
 
     def __init__(self, url, key):
         self.url = url
@@ -72,7 +72,7 @@
             "args": args
         }
 
-    def rhodecode_api_post(self, method, args):
+    def post(self, method, args):
         """Send a generic API post to Rhodecode.
 
         This will generate the UUID for validation check after the
@@ -92,7 +92,7 @@
             raise InvalidResponseIDError("UUID does not match.")
 
         if response["error"] is not None:
-            raise RhodecodeResponseError(response["error"])
+            raise ResponseError(response["error"])
 
         return response["result"]
 
@@ -102,7 +102,7 @@
             "group_name": name,
             "active": str(active)
         }
-        self.rhodecode_api_post("create_user_group", args)
+        self.post("create_user_group", args)
 
     def add_membership(self, group, username):
         """Add specific user to a group."""
@@ -110,7 +110,7 @@
             "usersgroupid": group,
             "userid": username
         }
-        result = self.rhodecode_api_post("add_user_to_user_group", args)
+        result = self.post("add_user_to_user_group", args)
         if not result["success"]:
             raise UserAlreadyInGroupError("User %s already in group %s." %
                                           (username, group))
@@ -121,7 +121,7 @@
             "usersgroupid": group,
             "userid": username
         }
-        result = self.rhodecode_api_post("remove_user_from_user_group", args)
+        result = self.post("remove_user_from_user_group", args)
         if not result["success"]:
             raise UserNotInGroupError("User %s not in group %s." %
                                       (username, group))
@@ -129,7 +129,7 @@
     def get_group_members(self, name):
         """Get the list of member usernames from a user group."""
         args = {"usersgroupid": name}
-        members = self.rhodecode_api_post("get_user_group", args)['members']
+        members = self.post("get_user_group", args)['members']
         member_list = []
         for member in members:
             member_list.append(member["username"])
@@ -138,12 +138,12 @@
     def get_group(self, name):
         """Return group info."""
         args = {"usersgroupid": name}
-        return self.rhodecode_api_post("get_user_group", args)
+        return self.post("get_user_group", args)
 
     def get_user(self, username):
         """Return user info."""
         args = {"userid": username}
-        return self.rhodecode_api_post("get_user", args)
+        return self.post("get_user", args)
 
 
 class LdapClient(object):
@@ -202,7 +202,7 @@
                                       config.get("default", "ldap_user"),
                                       config.get("default", "ldap_key"),
                                       config.get("default", "base_dn"))
-        self.rhodocode_api = RhodecodeAPI(config.get("default", "api_url"),
+        self.rhodocode_api = API(config.get("default", "api_url"),
                                           config.get("default", "api_key"))
 
     def update_groups_from_ldap(self):
@@ -211,7 +211,7 @@
         groups = self.ldap_client.get_groups()
         for group in groups:
             try:
-                self.rhodecode_api.create_repo_group(group)
+                self.kallithea_api.create_repo_group(group)
                 added += 1
             except Exception:
                 existing += 1
@@ -219,25 +219,25 @@
         return added, existing
 
     def update_memberships_from_ldap(self, group):
-        """Update memberships in rhodecode based on the LDAP groups."""
+        """Update memberships based on the LDAP groups."""
         groups = self.ldap_client.get_groups()
         group_users = self.ldap_client.get_group_users(groups, group)
 
         # Delete memberships first from each group which are not part
         # of the group any more.
-        rhodecode_members = self.rhodecode_api.get_group_members(group)
-        for rhodecode_member in rhodecode_members:
-            if rhodecode_member not in group_users:
+        members = self.kallithea_api.get_group_members(group)
+        for member in members:
+            if member not in group_users:
                 try:
                     self.rhodocode_api.remove_membership(group,
-                                                         rhodecode_member)
+                                                         member)
                 except UserNotInGroupError:
                     pass
 
         # Add memberships.
         for member in group_users:
             try:
-                self.rhodecode_api.add_membership(group, member)
+                self.kallithea_api.add_membership(group, member)
             except UserAlreadyInGroupError:
                 # TODO: handle somehow maybe..
                 pass
@@ -252,5 +252,5 @@
         # How should we handle this.. Either sync users as well at this step,
         # or just ignore those who don't exist. If we want the second case,
         # we need to find a way to recognize the right exception (we always get
-        # RhodecodeResponseError with no error code so maybe by return msg (?)
+        # ResponseError with no error code so maybe by return msg (?)
         sync.update_memberships_from_ldap(gr)
--- a/kallithea/bin/rhodecode_api.py	Wed Jul 02 19:04:33 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-# -*- coding: utf-8 -*-
-# 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/>.
-"""
-kallithea.bin.api
-~~~~~~~~~~~~~~~~~
-
-Api CLI client for RhodeCode
-
-:created_on: Jun 3, 2012
-:author: marcink
-:copyright: (c) 2013 RhodeCode GmbH.
-:license: GPLv3, see LICENSE for more details.
-"""
-
-from __future__ import with_statement
-import sys
-import argparse
-
-from kallithea.bin.base import json, api_call, RcConf, FORMAT_JSON, FORMAT_PRETTY
-
-
-def argparser(argv):
-    usage = (
-      "rhodecode-api [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
-      "[--config=CONFIG] [--save-config] "
-      "METHOD <key:val> <key2:val> ...\n"
-      "Create config file: rhodecode-api --apikey=<key> --apihost=http://your.kallithea.server --save-config"
-    )
-
-    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.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', nargs='?', type=str, default=None,
-            help='API method name to call followed by key:value attributes',
-    )
-    group.add_argument('--format', dest='format', type=str,
-            help='output format default: `%s` can '
-                 'be also `%s`' % (FORMAT_PRETTY, FORMAT_JSON),
-            default=FORMAT_PRETTY
-    )
-    args, other = parser.parse_known_args()
-    return parser, args, other
-
-
-def main(argv=None):
-    """
-    Main execution function for cli
-
-    :param 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.save_config:
-        if not api_credentials_given:
-            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)
-        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']
-    apihost = args.apihost or conf['apihost']
-    method = args.method
-
-    # if we don't have method here it's an error
-    if not method:
-        parser.error('Please specify method name')
-
-    try:
-        margs = dict(map(lambda s: s.split(':', 1), other))
-    except Exception:
-        sys.stderr.write('Error parsing arguments \n')
-        sys.exit()
-    if args.format == FORMAT_PRETTY:
-        print 'Calling method %s => %s' % (method, apihost)
-
-    json_resp = api_call(apikey, apihost, method, **margs)
-    error_prefix = ''
-    if json_resp['error']:
-        error_prefix = 'ERROR:'
-        json_data = json_resp['error']
-    else:
-        json_data = json_resp['result']
-    if args.format == FORMAT_JSON:
-        print json.dumps(json_data)
-    elif args.format == FORMAT_PRETTY:
-        print 'Server response \n%s%s' % (
-            error_prefix, json.dumps(json_data, indent=4, sort_keys=True)
-        )
-    return 0
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv))
--- a/kallithea/bin/rhodecode_backup.py	Wed Jul 02 19:04:33 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-# -*- coding: utf-8 -*-
-# 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/>.
-"""
-kallithea.bin.backup_manager
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Repositories backup manager, it allows to backups all
-repositories and send it to backup server using RSA key via ssh.
-
-:created_on: Feb 28, 2010
-:author: marcink
-:copyright: (c) 2013 RhodeCode GmbH.
-:license: GPLv3, see LICENSE for more details.
-"""
-
-import os
-import sys
-
-import logging
-import tarfile
-import datetime
-import subprocess
-
-logging.basicConfig(level=logging.DEBUG,
-                    format="%(asctime)s %(levelname)-5.5s %(message)s")
-
-
-class BackupManager(object):
-    def __init__(self, repos_location, rsa_key, backup_server):
-        today = datetime.datetime.now().weekday() + 1
-        self.backup_file_name = "rhodecode_repos.%s.tar.gz" % today
-
-        self.id_rsa_path = self.get_id_rsa(rsa_key)
-        self.repos_path = self.get_repos_path(repos_location)
-        self.backup_server = backup_server
-
-        self.backup_file_path = '/tmp'
-
-        logging.info('starting backup for %s', self.repos_path)
-        logging.info('backup target %s', self.backup_file_path)
-
-    def get_id_rsa(self, rsa_key):
-        if not os.path.isfile(rsa_key):
-            logging.error('Could not load id_rsa key file in %s', rsa_key)
-            sys.exit()
-        return rsa_key
-
-    def get_repos_path(self, path):
-        if not os.path.isdir(path):
-            logging.error('Wrong location for repositories in %s', path)
-            sys.exit()
-        return path
-
-    def backup_repos(self):
-        bckp_file = os.path.join(self.backup_file_path, self.backup_file_name)
-        tar = tarfile.open(bckp_file, "w:gz")
-
-        for dir_name in os.listdir(self.repos_path):
-            logging.info('backing up %s', dir_name)
-            tar.add(os.path.join(self.repos_path, dir_name), dir_name)
-        tar.close()
-        logging.info('finished backup of mercurial repositories')
-
-    def transfer_files(self):
-        params = {
-                  'id_rsa_key': self.id_rsa_path,
-                  'backup_file': os.path.join(self.backup_file_path,
-                                             self.backup_file_name),
-                  'backup_server': self.backup_server
-                  }
-        cmd = ['scp', '-l', '40000', '-i', '%(id_rsa_key)s' % params,
-               '%(backup_file)s' % params,
-               '%(backup_server)s' % params]
-
-        subprocess.call(cmd)
-        logging.info('Transfered file %s to %s', self.backup_file_name, cmd[4])
-
-    def rm_file(self):
-        logging.info('Removing file %s', self.backup_file_name)
-        os.remove(os.path.join(self.backup_file_path, self.backup_file_name))
-
-if __name__ == "__main__":
-
-    repo_location = '/home/repo_path'
-    backup_server = 'root@192.168.1.100:/backups/mercurial'
-    rsa_key = '/home/id_rsa'
-
-    B_MANAGER = BackupManager(repo_location, rsa_key, backup_server)
-    B_MANAGER.backup_repos()
-    B_MANAGER.transfer_files()
-    B_MANAGER.rm_file()
--- a/kallithea/bin/rhodecode_config.py	Wed Jul 02 19:04:33 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-# -*- coding: utf-8 -*-
-# 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/>.
-"""
-kallithea.bin.rhodecode_config
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-configuration generator for RhodeCode
-
-:created_on: Jun 18, 2013
-:author: marcink
-:copyright: (c) 2013 RhodeCode GmbH.
-:license: GPLv3, see LICENSE for more details.
-"""
-
-
-from __future__ import with_statement
-import os
-import sys
-import uuid
-import argparse
-from mako.template import Template
-TMPL = 'template.ini.mako'
-here = os.path.dirname(os.path.abspath(__file__))
-
-def argparser(argv):
-    usage = (
-      "rhodecode-config [-h] [--filename=FILENAME] [--template=TEMPLATE] \n"
-      "VARS optional specify extra template variable that will be available in "
-      "template. Use comma separated key=val format eg.\n"
-      "key1=val1,port=5000,host=127.0.0.1,elements='a\,b\,c'\n"
-    )
-
-    parser = argparse.ArgumentParser(
-        description='RhodeCode CONFIG generator with variable replacement',
-        usage=usage
-    )
-
-    ## config
-    group = parser.add_argument_group('CONFIG')
-    group.add_argument('--filename', help='Output ini filename.')
-    group.add_argument('--template', help='Mako template file to use instead of '
-                                          'the default builtin template')
-    group.add_argument('--raw', help='Store given mako template as raw without '
-                                     'parsing. Use this to create custom template '
-                                     'initially', action='store_true')
-    group.add_argument('--show-defaults', help='Show all default variables for '
-                                               'builtin template', action='store_true')
-    args, other = parser.parse_known_args()
-    return parser, args, other
-
-
-def _escape_split(text, sep):
-    """
-    Allows for escaping of the separator: e.g. arg='foo\, bar'
-
-    It should be noted that the way bash et. al. do command line parsing, those
-    single quotes are required. a shameless ripoff from fabric project.
-
-    """
-    escaped_sep = r'\%s' % sep
-
-    if escaped_sep not in text:
-        return text.split(sep)
-
-    before, _, after = text.partition(escaped_sep)
-    startlist = before.split(sep)  # a regular split is fine here
-    unfinished = startlist[-1]
-    startlist = startlist[:-1]
-
-    # recurse because there may be more escaped separators
-    endlist = _escape_split(after, sep)
-
-    # finish building the escaped value. we use endlist[0] becaue the first
-    # part of the string sent in recursion is the rest of the escaped value.
-    unfinished += sep + endlist[0]
-
-    return startlist + [unfinished] + endlist[1:]  # put together all the parts
-
-def _run(argv):
-    parser, args, other = argparser(argv)
-    if not len(sys.argv) > 1:
-        print parser.print_help()
-        sys.exit(0)
-    # defaults that can be overwritten by arguments
-    tmpl_stored_args = {
-        'http_server': 'waitress',
-        'lang': 'en',
-        'database_engine': 'sqlite',
-        'host': '127.0.0.1',
-        'port': 5000,
-        'error_aggregation_service': None,
-    }
-    if other:
-        # parse arguments, we assume only first is correct
-        kwargs = {}
-        for el in _escape_split(other[0], ','):
-            kv = _escape_split(el, '=')
-            if len(kv) == 2:
-                k, v = kv
-                kwargs[k] = v
-        # update our template stored args
-        tmpl_stored_args.update(kwargs)
-
-    # use default that cannot be replaced
-    tmpl_stored_args.update({
-        'uuid': lambda: uuid.uuid4().hex,
-        'here': os.path.abspath(os.curdir),
-    })
-    if args.show_defaults:
-        for k,v in tmpl_stored_args.iteritems():
-            print '%s=%s' % (k, v)
-        sys.exit(0)
-    try:
-        # built in template
-        tmpl_file = os.path.join(here, TMPL)
-        if args.template:
-            tmpl_file = args.template
-
-        with open(tmpl_file, 'rb') as f:
-            tmpl_data = f.read()
-            if args.raw:
-                tmpl = tmpl_data
-            else:
-                tmpl = Template(tmpl_data).render(**tmpl_stored_args)
-        with open(args.filename, 'wb') as f:
-            f.write(tmpl)
-        print 'Wrote new config file in %s' % (os.path.abspath(args.filename))
-
-    except Exception:
-        from mako import exceptions
-        print exceptions.text_error_template().render()
-
-def main(argv=None):
-    """
-    Main execution function for cli
-
-    :param argv:
-    """
-    if argv is None:
-        argv = sys.argv
-
-    try:
-        return _run(argv)
-    except Exception:
-        raise
-
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv))
--- a/kallithea/bin/rhodecode_gist.py	Wed Jul 02 19:04:33 2014 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-# -*- coding: utf-8 -*-
-# 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/>.
-"""
-kallithea.bin.rhodecode_gist
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Gist CLI client for RhodeCode
-
-:created_on: May 9, 2013
-:author: marcink
-:copyright: (c) 2013 RhodeCode GmbH.
-:license: GPLv3, see LICENSE for more details.
-"""
-
-from __future__ import with_statement
-import os
-import sys
-import stat
-import argparse
-import fileinput
-
-from kallithea.bin.base import json, api_call, RcConf, FORMAT_JSON, FORMAT_PRETTY
-
-
-def argparser(argv):
-    usage = (
-      "rhodecode-gist [-h] [--format=FORMAT] [--apikey=APIKEY] [--apihost=APIHOST] "
-      "[--config=CONFIG] [--save-config] [GIST OPTIONS] "
-      "[filename or stdin use - for terminal stdin ]\n"
-      "Create config file: rhodecode-gist --apikey=<key> --apihost=http://your.kallithea.server --save-config"
-    )
-
-    parser = argparse.ArgumentParser(description='RhodeCode Gist 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.add_argument('--config', help='config file path DEFAULT: ~/.config/kallithea')
-    group.add_argument('--save-config', action='store_true',
-                       help='save the given config into a file')
-
-    group = parser.add_argument_group('GIST')
-    group.add_argument('-p', '--private', action='store_true',
-                       help='create private Gist')
-    group.add_argument('-f', '--filename',
-                       help='set uploaded gist filename, '
-                            'also defines syntax highlighting')
-    group.add_argument('-d', '--description', help='Gist description')
-    group.add_argument('-l', '--lifetime', metavar='MINUTES',
-                       help='gist lifetime in minutes, -1 (DEFAULT) is forever')
-    group.add_argument('--format', dest='format', type=str,
-                       help='output format DEFAULT: `%s` can '
-                       'be also `%s`' % (FORMAT_PRETTY, FORMAT_JSON),
-            default=FORMAT_PRETTY
-    )
-    args, other = parser.parse_known_args()
-    return parser, args, other
-
-
-def _run(argv):
-    conf = None
-    parser, args, other = argparser(argv)
-
-    api_credentials_given = (args.apikey and args.apihost)
-    if args.save_config:
-        if not api_credentials_given:
-            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)
-        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']
-    DEFAULT_FILENAME = 'gistfile1.txt'
-    if other:
-        # skip multifiles for now
-        filename = other[0]
-        if filename == '-':
-            filename = DEFAULT_FILENAME
-            gist_content = ''
-            for line in fileinput.input('-'):
-                gist_content += line
-        else:
-            with open(filename, 'rb') as f:
-                gist_content = f.read()
-
-    else:
-        filename = DEFAULT_FILENAME
-        gist_content = None
-        # little bit hacky but cross platform check where the
-        # stdin comes from we skip the terminal case it can be handled by '-'
-        mode = os.fstat(0).st_mode
-        if stat.S_ISFIFO(mode):
-            # "stdin is piped"
-            gist_content = sys.stdin.read()
-        elif stat.S_ISREG(mode):
-            # "stdin is redirected"
-            gist_content = sys.stdin.read()
-        else:
-            # "stdin is terminal"
-            pass
-
-    # make sure we don't upload binary stuff
-    if gist_content and '\0' in gist_content:
-        raise Exception('Error: binary files upload is not possible')
-
-    filename = os.path.basename(args.filename or filename)
-    if gist_content:
-        files = {
-            filename: {
-                'content': gist_content,
-                'lexer': None
-            }
-        }
-
-        margs = dict(
-            lifetime=args.lifetime,
-            description=args.description,
-            gist_type='private' if args.private else 'public',
-            files=files
-        )
-
-        json_data = api_call(apikey, host, 'create_gist', **margs)['result']
-        if args.format == FORMAT_JSON:
-            print json.dumps(json_data)
-        elif args.format == FORMAT_PRETTY:
-            print json_data
-            print 'Created %s gist %s' % (json_data['gist']['type'],
-                                          json_data['gist']['url'])
-    return 0
-
-
-def main(argv=None):
-    """
-    Main execution function for cli
-
-    :param argv:
-    """
-    if argv is None:
-        argv = sys.argv
-
-    try:
-        return _run(argv)
-    except Exception, e:
-        print e
-        return 1
-
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv))
--- a/kallithea/tests/scripts/create_rc.sh	Wed Jul 02 19:04:33 2014 -0400
+++ b/kallithea/tests/scripts/create_rc.sh	Wed Jul 02 19:04:39 2014 -0400
@@ -6,12 +6,12 @@
 echo "run those after running server"
 paster serve rc.ini --pid-file=rc.pid --daemon
 sleep 3
-rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@example.com
-rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@example.com
-rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@example.com
-rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user_group group_name:demo12
-rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo1
-rhodecode-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo2
+kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@example.com
+kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@example.com
+kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@example.com
+kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user_group group_name:demo12
+kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo1
+kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo2
 echo "killing server"
 kill `cat rc.pid`
 rm rc.pid
--- a/setup.py	Wed Jul 02 19:04:33 2014 -0400
+++ b/setup.py	Wed Jul 02 19:04:39 2014 -0400
@@ -158,9 +158,9 @@
     paster_plugins=['PasteScript', 'Pylons'],
     entry_points="""
     [console_scripts]
-    rhodecode-api =    kallithea.bin.rhodecode_api:main
-    rhodecode-gist =   kallithea.bin.rhodecode_gist:main
-    rhodecode-config = kallithea.bin.rhodecode_config:main
+    kallithea-api =    kallithea.bin.kallithea_api:main
+    kallithea-gist =   kallithea.bin.kallithea_gist:main
+    kallithea-config = kallithea.bin.kallithea_config:main
 
     [paste.app_factory]
     main = kallithea.config.middleware:make_app