Completed
Push — master ( 2a74fd...6305c6 )
by Konrad
01:23
created

db_sync_tool.utility.helper   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 251
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 43
eloc 115
dl 0
loc 251
rs 8.96
c 0
b 0
f 0

13 Functions

Rating   Name   Duplication   Size   Complexity  
A clean_up_dump_dir() 0 33 4
A check_os() 0 10 1
A clean_up() 0 9 3
A get_dump_dir() 0 10 2
A check_and_create_dump_dir() 0 10 1
A create_local_temporary_data_dir() 0 8 2
A get_command() 0 11 3
A remove_temporary_data_dir() 0 11 2
A get_ssh_host_name() 0 20 5
A check_file_exists() 0 8 1
A dict_to_args() 0 17 5
A run_script() 0 27 4
C confirm() 0 38 10

How to fix   Complexity   

Complexity

Complex classes like db_sync_tool.utility.helper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#!/usr/bin/env python3
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
# -*- coding: future_fstrings -*-
3
4
import shutil
5
import os
6
from db_sync_tool.utility import mode, system, output
7
from db_sync_tool.remote import utility as remote_utility
8
9
10
def clean_up():
11
    """
12
    Clean up
13
    :return:
14
    """
15
    if not mode.is_import():
16
        remote_utility.remove_target_database_dump()
17
        if mode.get_sync_mode() == mode.SyncMode.PROXY:
18
            remove_temporary_data_dir()
19
20
21
def remove_temporary_data_dir():
22
    """
23
    Remove temporary data directory for storing database dump files
24
    :return:
25
    """
26
    if os.path.exists(system.default_local_sync_path):
27
        shutil.rmtree(system.default_local_sync_path)
28
        output.message(
29
            output.Subject.LOCAL,
30
            'Cleaning up',
31
            True
32
        )
33
34
35
def clean_up_dump_dir(client, path, num=5):
36
    """
37
    Clean up the dump directory from old dump files (only affect .sql and .tar.gz files)
38
    :param client:
39
    :param path:
40
    :param num:
41
    :return:
42
    """
43
    # Distinguish stat command on os system (Darwin|Linux)
44
    if check_os(client).strip() == 'Darwin':
45
        _command = get_command(client, 'stat') + ' -f "%Sm %N" ' + path + ' | ' + get_command(client,
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (101/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
46
                                                                                              'sort') + ' -rn | ' + get_command(
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (128/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
47
            client, 'grep') + ' -E ".tar.gz|.sql"'
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (add 86 spaces).
Loading history...
48
    else:
49
        _command = get_command(client, 'stat') + ' -c "%y %n" ' + path + ' | ' + get_command(client,
50
                                                                                             'sort') + ' -rn | ' + get_command(
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (127/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
51
            client, 'grep') + ' -E ".tar.gz|.sql"'
0 ignored issues
show
Coding Style introduced by
Wrong hanging indentation (add 85 spaces).
Loading history...
52
53
    # List files in directory sorted by change date
54
    _files = mode.run_command(
55
        _command,
56
        client,
57
        True
58
    ).splitlines()
59
60
    for i in range(len(_files)):
0 ignored issues
show
unused-code introduced by
Consider using enumerate instead of iterating with range and len
Loading history...
61
        _filename = _files[i].rsplit(' ', 1)[-1]
62
63
        # Remove oldest files chosen by keep_dumps count
64
        if not i < num:
65
            mode.run_command(
66
                'rm ' + _filename,
67
                client
68
            )
69
70
71
def check_os(client):
72
    """
73
    Check which system is running (Linux|Darwin)
74
    :param client:
75
    :return:
76
    """
77
    return mode.run_command(
78
        get_command(client, 'uname') + ' -s',
79
        client,
80
        True
81
    )
82
83
84
def get_command(client, command):
85
    """
86
    Get command helper for overriding default commands on the given client
87
    :param client:
88
    :param command:
89
    :return: String command
90
    """
91
    if 'console' in system.config[client]:
92
        if command in system.config[client]['console']:
93
            return system.config[client]['console'][command]
94
    return command
95
96
97
def get_dump_dir(client):
98
    """
99
    Get database dump directory by client
100
    :param client:
101
    :return: String path
102
    """
103
    if system.config[f'default_{client}_dump_dir']:
0 ignored issues
show
unused-code introduced by
Unnecessary "else" after "return"
Loading history...
104
        return '/tmp/'
105
    else:
106
        return system.config[client]['dump_dir']
107
108
109
def check_and_create_dump_dir(client, path):
110
    """
111
    Check if a path exists on the client system and creates the given path if necessary
112
    :param client:
113
    :param path:
114
    :return:
115
    """
116
    mode.run_command(
117
        '[ ! -d "' + path + '" ] && mkdir -p "' + path + '"',
118
        client
119
    )
120
121
122
def get_ssh_host_name(client, with_user=False):
123
    """
124
    Format ssh host name depending on existing client name
125
    :param client:
126
    :param with_user:
127
    :return:
128
    """
129
    if not 'user' in system.config[client] and not 'host' in system.config[client]:
130
        return ''
131
132
    if with_user:
133
        _host = system.config[client]['user'] + '@' + system.config[client]['host']
134
    else:
135
        _host = system.config[client]['host']
136
137
    if 'name' in system.config[client]:
0 ignored issues
show
unused-code introduced by
Unnecessary "else" after "return"
Loading history...
138
        return output.CliFormat.BOLD + system.config[client][
139
            'name'] + output.CliFormat.ENDC + output.CliFormat.BLACK + ' (' + _host + ')' + output.CliFormat.ENDC
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (113/100).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
140
    else:
141
        return _host
142
143
144
def create_local_temporary_data_dir():
145
    """
146
    Create local temporary data dir
147
    :return:
148
    """
149
    # @ToDo: Combine with check_and_create_dump_dir()
150
    if not os.path.exists(system.default_local_sync_path):
151
        os.mkdir(system.default_local_sync_path)
152
153
154
def dict_to_args(dict):
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in dict.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
155
    """
156
    Convert an dictionary to a args list
157
    :param dict: Dictionary
158
    :return: List
159
    """
160
    _args = []
161
    for key, val in dict.items():
162
        if isinstance(val, bool):
163
            if val:
164
                _args.append(f'--{key}')
165
        else:
166
            _args.append(f'--{key}')
167
            _args.append(str(val))
168
    if len(_args) == 0:
169
        return None
170
    return _args
171
172
173
def check_file_exists(client, path):
174
    """
175
    Check if a file exists
176
    :param client: String
177
    :param path: String file path
178
    :return: Boolean
179
    """
180
    return mode.run_command(f'[ -f {path} ] && echo "1"', client, True) == '1'
181
182
183
def run_script(client=None, script='before'):
184
    """
185
    Executing script command
186
    :param client: String
187
    :param script: String
188
    :return:
189
    """
190
    if client is None:
191
        _config = system.config
192
        _subject = output.Subject.LOCAL
193
        client = mode.Client.LOCAL
194
    else:
195
        _config = system.config[client]
196
        _subject = output.host_to_subject(client)
197
198
    if not 'scripts' in _config:
0 ignored issues
show
Unused Code introduced by
Consider changing "not 'scripts' in _config" to "'scripts' not in _config"
Loading history...
199
        return
200
201
    if f'{script}' in _config['scripts']:
202
        output.message(
203
            _subject,
204
            f'Running script {client}',
205
            True
206
        )
207
        mode.run_command(
208
            _config['scripts'][script],
209
            client
210
        )
211
212
213
def confirm(prompt=None, resp=False):
214
    """
215
    https://code.activestate.com/recipes/541096-prompt-the-user-for-confirmation/
216
217
    prompts for yes or no response from the user. Returns True for yes and
218
    False for no.
219
220
    'resp' should be set to the default value assumed by the caller when
221
    user simply types ENTER.
222
223
    >>> confirm(prompt='Create Directory?', resp=True)
224
    Create Directory? [Y|n]:
225
    True
226
    >>> confirm(prompt='Create Directory?', resp=False)
227
    Create Directory? [y|N]:
228
    False
229
230
    """
231
232
    if prompt is None:
233
        prompt = 'Confirm'
234
235
    if resp:
236
        prompt = '%s [%s|%s]: ' % (prompt, 'Y', 'n')
237
    else:
238
        prompt = '%s [%s|%s]: ' % (prompt, 'y', 'N')
239
240
    while True:
241
        ans = input(prompt)
242
        if not ans:
243
            return resp
244
        if ans not in ['y', 'Y', 'n', 'N']:
245
            print('Please enter y or n.')
246
            continue
247
        if ans == 'y' or ans == 'Y':
0 ignored issues
show
Unused Code introduced by
Consider merging these comparisons with "in" to "ans in ('y', 'Y')"
Loading history...
248
            return True
249
        if ans == 'n' or ans == 'N':
0 ignored issues
show
Unused Code introduced by
Consider merging these comparisons with "in" to "ans in ('n', 'N')"
Loading history...
250
            return False
251