Passed
Pull Request — master (#8)
by
unknown
04:52
created

cli()   A

Complexity

Conditions 2

Size

Total Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.9684

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 2
c 3
b 0
f 0
dl 0
loc 29
ccs 4
cts 19
cp 0.2105
crap 3.9684
rs 9.184
1
"""
2
CLI Tool that wrap docker-compose and build it from what has been taken from config
3
"""
4
5 1
import os
6 1
import subprocess
7 1
import sys
8 1
import click
9 1
from stakkr import package_utils
10 1
from stakkr.configreader import Config
11
12
13 1
@click.command(help="Wrapper for docker-compose",
14
               context_settings=dict(ignore_unknown_options=True))
15 1
@click.option('--config', '-c', help="Override the conf/compose.ini")
16 1
@click.argument('command', nargs=-1, type=click.UNPROCESSED)
17 1
def cli(config: str, command):
18
    """Command line entry point"""
19
20
    main_config = get_main_config(config)
21
    set_env_values_from_conf(main_config)
22
23
    project_name = main_config.get('project_name')
24
    os.putenv('COMPOSE_PROJECT_NAME', project_name)
25
26
    # What to load
27
    compose_file = package_utils.get_file('static', 'docker-compose.yml')
28
    activated_services = get_enabled_services(main_config.get('services'))
29
30
    # Create the command
31
    services = []
32
    for service in activated_services:
33
        services.append('-f')
34
        services.append(service)
35
36
    base_cmd = ['docker-compose', '-f', compose_file] + services + ['-p', project_name]
37
38
    msg = click.style('[VERBOSE] ', fg='green')
39
    msg += 'Compose command: ' + ' '.join(base_cmd + list(command))
40
    click.echo(msg, err=True)
41
    subprocess.call(base_cmd + list(command))
42
43
44 1
def add_services_from_plugins(available_services: list):
45
    """Read plugin path and extract services in subdirectories services/"""
46
47 1
    from pkg_resources import iter_entry_points
48
49
    # Override services with plugins
50 1
    for entry in iter_entry_points('stakkr.plugins'):
51
        plugin_dir = str(entry).split('=')[0].strip()
52
        services_dir = package_utils.get_venv_basedir() + '/plugins/' + plugin_dir + '/services'
53
54
        conf_files = _get_services_from_dir(services_dir)
55
        for conf_file in conf_files:
56
            available_services[conf_file[:-4]] = services_dir + '/' + conf_file
57
58 1
    return available_services
59
60
61 1
def add_local_services(available_services: list):
62
    """Get services in the virtualenv services/ directory, so specific to that stakkr"""
63
64 1
    services_dir = package_utils.get_venv_basedir() + '/services'
65
66 1
    conf_files = _get_services_from_dir(services_dir)
67 1
    for conf_file in conf_files:
68
        available_services[conf_file[:-4]] = services_dir + '/' + conf_file
69
70 1
    return available_services
71
72
73 1
def get_available_services():
74
    """Get standard services bundled with stakkr"""
75
76 1
    services_dir = package_utils.get_dir('static') + '/services/'
77 1
    conf_files = _get_services_from_dir(services_dir)
78
79 1
    services = dict()
80 1
    for conf_file in conf_files:
81 1
        services[conf_file[:-4]] = services_dir + conf_file
82
83 1
    return services
84
85
86 1
def get_enabled_services(configured_services: list):
87
    """Compile all available services : standard, plugins, local install"""
88
89 1
    available_services = get_available_services()
90 1
    available_services = add_services_from_plugins(available_services)
91 1
    available_services = add_local_services(available_services)
92
93 1
    services_files = []
94 1
    for service in configured_services:
95 1
        if service not in available_services:
96 1
            msg = 'Error: service "{}" has no configuration file. '.format(service)
97 1
            msg += 'Check your compose.ini'
98 1
            click.secho(msg, fg='red')
99 1
            sys.exit(1)
100 1
        services_files.append(available_services[service])
101
102 1
    return services_files
103
104 1
def get_configured_services(config_file: str = None):
105
    """Get services set in compose.ini"""
106
107 1
    configured_services = get_main_config(config_file).get('services')
108 1
    return configured_services
109
110
111 1
def get_main_config(config: str):
112
    """Read main compose.ini file"""
113
114 1
    config = Config(config)
115 1
    main_config = config.read()
116
117 1
    if main_config is False:
118
        config.display_errors()
119
        sys.exit(1)
120
121 1
    return main_config['main']
122
123
124 1
def set_env_values_from_conf(config: list):
125
    """Define environment variables to be used in services yaml"""
126
127
    os.environ['DOCKER_UID'] = _get_uid(config.pop('uid'))
128
    os.environ['DOCKER_GID'] = _get_gid(config.pop('gid'))
129
    os.environ['COMPOSE_BASE_DIR'] = package_utils.get_venv_basedir()
130
131
    for parameter, value in config.items():
132
        parameter = 'DOCKER_{}'.format(parameter.replace('.', '_').upper())
133
        os.environ[parameter] = str(value)
134
135
136 1
def _get_services_from_dir(services_dir: str):
137 1
    if os.path.isdir(services_dir) is False:
138
        return []
139
140 1
    return [service for service in os.listdir(services_dir) if service.endswith('.yml')]
141
142
143 1
def _get_uid(uid: int):
144 1
    if uid is not None:
145 1
        return str(uid)
146
147 1
    return '1000' if os.name == 'nt' else str(os.getuid())
148
149
150 1
def _get_gid(gid: int):
151 1
    if gid is not None:
152 1
        return str(gid)
153
154 1
    return '1000' if os.name == 'nt' else str(os.getgid())
155
156
157 1
if __name__ == '__main__':
158
    cli()
159