Files @ 747cc853b5e9
Branch filter:

Location: kallithea/kallithea/bin/kallithea_cli_base.py

Thomas De Schampheleire
release: merge default to stable for 0.7.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/>.

import configparser
import functools
import logging.config
import os
import re
import sys

import click
import paste.deploy

import kallithea
import kallithea.config.application


# kallithea_cli is usually invoked through the 'kallithea-cli' wrapper script
# that is installed by setuptools, as specified in setup.py console_scripts
# entry_points. The script will be using the right virtualenv (if any), and for
# Unix, it will contain #! pointing at the right python executable. The script
# also makes sure sys.argv[0] points back at the script path, and that is what
# can be used to invoke 'kallithea-cli' later.
kallithea_cli_path = sys.argv[0]


def read_config(ini_file_name, strip_section_prefix):
    """Read ini_file_name content, and for all sections like '[X:Y]' where X is
    strip_section_prefix, replace the section name with '[Y]'."""

    def repl(m):
        if m.group(1) == strip_section_prefix:
            return '[%s]' % m.group(2)
        return m.group(0)

    with open(ini_file_name) as f:
        return re.sub(r'^\[([^:]+):(.*)]', repl, f.read(), flags=re.MULTILINE)


# This placeholder is the main entry point for the kallithea-cli command
@click.group(context_settings=dict(help_option_names=['-h', '--help']))
def cli():
    """Various commands to manage a Kallithea instance."""

def register_command(needs_config_file=False, config_file_initialize_app=False, hidden=False):
    """Register a kallithea-cli subcommand.

    If one of the needs_config_file flags are true, a config file must be specified
    with -c and it is read and logging is configured. The configuration is
    available in the kallithea.CONFIG dict.

    If config_file_initialize_app is true, Kallithea, TurboGears global state
    (including tg.config), and database access will also be fully initialized.
    """
    cli_command = cli.command(hidden=hidden)
    if needs_config_file or config_file_initialize_app:
        def annotator(annotated):
            @click.option('--config_file', '-c', help="Path to .ini file with app configuration.",
                type=click.Path(dir_okay=False, exists=True, readable=True), required=True)
            @functools.wraps(annotated) # reuse meta data from the wrapped function so click can see other options
            def runtime_wrapper(config_file, *args, **kwargs):
                path_to_ini_file = os.path.realpath(config_file)
                config = paste.deploy.appconfig('config:' + path_to_ini_file)
                cp = configparser.ConfigParser(strict=False)
                cp.read_string(read_config(path_to_ini_file, strip_section_prefix=annotated.__name__))
                logging.config.fileConfig(cp,
                    {'__file__': path_to_ini_file, 'here': os.path.dirname(path_to_ini_file)})
                if needs_config_file:
                    annotated(*args, config=config, **kwargs)
                if config_file_initialize_app:
                    kallithea.config.application.make_app(config.global_conf, **config.local_conf)
                    annotated(*args, **kwargs)
            return cli_command(runtime_wrapper)
        return annotator
    return cli_command