Passed
Push — master ( 6e272c...bcf863 )
by Konrad
01:50
created

lighthouse_garden.utility.system   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 137
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 19
eloc 71
dl 0
loc 137
rs 10
c 0
b 0
f 0

6 Functions

Rating   Name   Duplication   Size   Complexity  
A clear_data() 0 13 2
A check_args() 0 14 2
A check_lighthouse_version() 0 13 2
A run_command() 0 24 5
B check_config() 0 23 7
A check_path() 0 8 1
1
#!/usr/bin/env python3
0 ignored issues
show
introduced by
Missing module docstring
Loading history...
2
# -*- coding: future_fstrings -*-
3
4
import json
5
import os
6
import shutil
7
import subprocess
8
import sys
9
10
from lighthouse_garden.utility import output
11
from lighthouse_garden.lighthouse import utility
12
13
config = {
14
    'verbose': False,
15
    'mute': False,
16
    'run': 1,
17
    'export': False,
18
    'export_path': None,
19
    'config_file_path': None,
20
    'data_dir': 'd/',
21
    'keep_history': 0,
22
    'title': 'Lighthouse Garden',
23
    'description': 'Monitoring performance data by Google Lighthouse',
24
    'lighthouse': {
25
        'chrome_flags': '--no-sandbox --headless --disable-gpu --ignore-certificate-errors --disable-dev-shm-usage',
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (116/100).

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

Loading history...
26
        'options': '--quiet --no-enable-error-reporting --preset=desktop --disable-storage-reset'
27
    }
28
}
29
30
31
def check_args(config_file=None,
32
               verbose=False):
33
    """
34
35
    :param config_file:
36
    :param verbose:
37
    :return:
38
    """
39
    global config
0 ignored issues
show
Coding Style Naming introduced by
Constant name "config" doesn't conform to UPPER_CASE naming style ('([^\\W\\da-z][^\\Wa-z]*|__.*__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
40
41
    config['verbose'] = verbose
42
43
    if not config_file is None:
44
        config['config_file_path'] = config_file
45
46
47
def check_config(additional_config={}):
0 ignored issues
show
Bug Best Practice introduced by
The default value {} might cause unintended side-effects.

Objects as default values are only created once in Python and not on each invocation of the function. If the default object is modified, this modification is carried over to the next invocation of the method.

# Bad:
# If array_param is modified inside the function, the next invocation will
# receive the modified object.
def some_function(array_param=[]):
    # ...

# Better: Create an array on each invocation
def some_function(array_param=None):
    array_param = array_param or []
    # ...
Loading history...
48
    """
49
    Checking configuration information by file or dictionary
50
    :param additional_config: Dictionary
51
    :return:
52
    """
53
    global config
0 ignored issues
show
Coding Style Naming introduced by
Constant name "config" doesn't conform to UPPER_CASE naming style ('([^\\W\\da-z][^\\Wa-z]*|__.*__)$' pattern)

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
Coding Style introduced by
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
54
55
    if config['config_file_path'] is None and additional_config == {}:
56
        sys.exit(f'{output.Subject.ERROR} Configuration is missing')
57
58
    if additional_config:
59
        config.update(additional_config)
60
61
    _config_file_path = config['config_file_path']
62
    if not _config_file_path is None:
63
        if os.path.isfile(_config_file_path):
64
            with open(_config_file_path, 'r') as read_file:
65
                config.update(json.load(read_file))
66
                output.println(
67
                    f'{output.Subject.INFO} Loading host configuration {output.CliFormat.BLACK}{_config_file_path}{output.CliFormat.ENDC}', verbose_only=True)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (158/100).

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

Loading history...
68
        else:
69
            sys.exit(f'{output.Subject.ERROR} Local configuration not found: {config["config_file_path"]}')
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (107/100).

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

Loading history...
70
71
72
def run_command(command, return_output=False, allow_fail=False):
0 ignored issues
show
Unused Code introduced by
Either all return statements in a function should return an expression, or none of them should.
Loading history...
73
    """
74
    Run local command
75
    :param command: String Shell command
76
    :param return_output: Boolean Return shell command output
77
    :param allow_fail: Boolean
78
    :return:
79
    """
80
    output.println(
81
        f'{output.Subject.DEBUG}{output.Subject.CMD} {output.CliFormat.BLACK}{command}{output.CliFormat.ENDC}', verbose_only=True)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (130/100).

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

Loading history...
82
83
    res = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
84
85
    out, err = res.communicate()
86
87
    if res.wait() != 0 and err.decode() != '':
88
        _error_message = f'{output.Subject.ERROR} {err.decode()}'
89
        if allow_fail:
90
            output.println(_error_message)
91
        else:
92
            sys.exit(_error_message)
93
94
    if return_output:
95
        return out.decode()
96
97
98
def check_lighthouse_version():
99
    """
100
    Check sshpass version
101
    :return:
102
    """
103
    _version = run_command('lighthouse --version', return_output=True)
104
105
    if _version:
106
        output.println(
107
            f'{output.Subject.INFO} lighthouse version {_version}',
108
            verbose_only=True
109
        )
110
        config['lighthouse']['version'] = _version
111
112
113
def check_path(path):
114
    """
115
    Create a path on the system if not exists
116
    :param path: String Directory path
117
    :return:
118
    """
119
    run_command(
120
        f'[ ! -d "{path}" ] && mkdir -p "{path}"'
121
    )
122
123
124
def clear_data():
125
    """
126
    Clear the performance data and the lighthouse garden dashboard
127
    :return:
128
    """
129
    output.println(f'{output.Subject.INFO} Clear data')
130
    _file_path = f'{config["export_path"]}index.html'
131
    _dir_path = utility.get_data_dir()
132
133
    if os.path.isfile(_file_path):
134
        os.remove(_file_path)
135
136
    shutil.rmtree(_dir_path)
137