Passed
Push — master ( 97f4cf...78acb5 )
by Matěj
06:08 queued 12s
created

oval_graph.client.Client.get_questions()   A

Complexity

Conditions 1

Size

Total Lines 13
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 10
nop 1
dl 0
loc 13
ccs 5
cts 5
cp 1
crap 1
rs 9.9
c 0
b 0
f 0
1 1
import re
2 1
import argparse
3 1
import tempfile
4 1
import os
5 1
import webbrowser
6 1
import json
7 1
import shutil
8 1
from datetime import datetime
9 1
import sys
10
11 1
from .xml_parser import XmlParser
12 1
from .exceptions import NotChecked
13 1
from ._builder_html_graph import BuilderHtmlGraph
14 1
from .__init__ import __version__
15
16
17 1
class Client():
18 1
    def __init__(self, args):
19 1
        self.parser = None
20 1
        self.MESSAGES = self._get_message()
21 1
        self.arg = self.parse_arguments(args)
22 1
        self.hide_passing_tests = self.arg.hide_passing_tests
23 1
        self.source_filename = self.arg.source_filename
24 1
        self.rule_name = self.arg.rule_id
25 1
        self.out = self.arg.output
26 1
        self.all_rules = self.arg.all
27 1
        self.all_in_one = None
28 1
        self.display_html = None
29 1
        self.isatty = sys.stdout.isatty()
30 1
        self.show_failed_rules = False
31 1
        self.show_not_selected_rules = False
32 1
        self.xml_parser = XmlParser(
33
            self.source_filename)
34 1
        self.parts = self.get_src('parts')
35 1
        self.START_OF_FILE_NAME = 'graph-of-'
36 1
        self.date = str(datetime.now().strftime("-%d_%m_%Y-%H_%M_%S"))
37 1
        self.verbose = self.arg.verbose
38
39 1
    def _get_message(self):
40 1
        MESSAGES = {
41
            'description': '',
42
            'source_filename': '',
43
        }
44 1
        return MESSAGES
45
46 1
    def print_red_text(self, text):
47
        CRED = '\033[91m'
48
        CEND = '\033[0m'
49
        print(CRED + str(text) + CEND)
50
51 1
    def run_gui_and_return_answers(self):
52 1
        if self.isatty:
53 1
            if self.all_rules:
54
                return self._get_rules()
55
            else:
56 1
                try:
57 1
                    import inquirer
58 1
                    return inquirer.prompt(self.get_questions())
59 1
                except ImportError:
60 1
                    print(self.get_selection_rules())
61 1
                    return None
62
        else:
63 1
            return self._get_rules()
64
65 1
    def _get_rules(self):
66 1
        return {
67
            'rules': self._get_only_fail_rule(
68
                self.search_rules_id())} if self.show_failed_rules else {
69
            'rules': self.search_rules_id()}
70
71 1
    def get_list_of_matched_rules(self):
72 1
        return self._get_only_fail_rule(
73
            self.search_rules_id()) if self.show_failed_rules else self.search_rules_id()
74
75 1
    def get_list_of_lines(self):
76 1
        lines = ['== The Rule ID regular expressions ==']
77 1
        for rule in self.get_list_of_matched_rules():
78 1
            lines.append("^" + rule + "$")
79 1
        if self.show_not_selected_rules:
80 1
            for line in self.get_lines_of_wanted_not_selected_rules():
81 1
                lines.append(line)
82 1
        lines.append(
83
            "Interactive rule selection is not available,"
84
            " because inquirer is not installed."
85
            " Copy id of the rule you want to visualize and"
86
            " paste it into a command with regular"
87
            " expression characters(^$).\n"
88
            "Alternatively, use the --all or --all-in-one arguments.")
89 1
        return lines
90
91 1
    def get_selection_rules(self):
92 1
        return "\n".join(self.get_list_of_lines())
93
94 1
    def get_lines_of_wanted_not_selected_rules(self):
95 1
        out = []
96 1
        out.append('== The not selected rule IDs ==')
97 1
        for rule in self._get_wanted_rules_from_array_of_IDs(
98
                self.xml_parser.notselected_rules):
99 1
            out.append(rule + '(Not selected)')
100 1
        return out
101
102 1
    def get_choices(self):
103 1
        if self.show_not_selected_rules:
104 1
            print("\n".join(self.get_lines_of_wanted_not_selected_rules()))
105 1
        return self.get_list_of_matched_rules()
106
107 1
    def get_questions(self):
108 1
        choices = self.get_choices()
109 1
        from inquirer.questions import Checkbox as checkbox
110 1
        questions = [
111
            checkbox(
112
                'rules',
113
                message=(
114
                    "= The Rules IDs = (move - UP and DOWN arrows,"
115
                    " select - SPACE or LEFT and RIGHT arrows, submit - ENTER)"),
116
                choices=choices,
117
            ),
118
        ]
119 1
        return questions
120
121 1
    def _get_only_fail_rule(self, rules):
122 1
        return list(
123
            filter(
124
                lambda rule: self.xml_parser.used_rules[rule]['result'] == 'fail',
125
                rules))
126
127 1
    def _get_wanted_rules_from_array_of_IDs(self, rules):
128 1
        return [
129
            x for x in rules if re.search(
130
                self.rule_name, x)]
131
132 1
    def search_rules_id(self):
133 1
        return self._check_rules_id(
134
            self._get_wanted_rules_from_array_of_IDs(
135
                self.xml_parser.used_rules.keys()),
136
            self._get_wanted_rules_from_array_of_IDs(
137
                self.xml_parser.notselected_rules))
138
139 1
    def _check_rules_id(self, rules, notselected_rules):
140 1
        if len(notselected_rules) and not rules:
141 1
            raise ValueError(
142
                ('Rule(s) "{}" was not selected, '
143
                 "so there are no results. The rule is"
144
                 ' "notselected" because it'
145
                 " wasn't a part of the executed profile"
146
                 " and therefore it wasn't evaluated "
147
                 "during the scan.")
148
                .format(notselected_rules))
149 1
        elif not notselected_rules and not rules:
150 1
            raise ValueError('404 rule "{}" not found!'.format(self.rule_name))
151
        else:
152 1
            return rules
153
154 1
    def get_save_src(self, rule):
155 1
        if self.out is not None:
156 1
            os.makedirs(self.out, exist_ok=True)
157 1
            return os.path.join(
158
                self.out,
159
                self.START_OF_FILE_NAME + rule + '.html')
160 1
        return os.path.join(
161
            tempfile.gettempdir(),
162
            self.START_OF_FILE_NAME + rule + '.html')
163
164 1
    def get_src(self, src):
165 1
        _dir = os.path.dirname(os.path.realpath(__file__))
166 1
        return str(os.path.join(_dir, src))
167
168 1
    def _build_and_save_html(self, dict_oval_trees, src, rules, out_src):
169 1
        builder = BuilderHtmlGraph(
170
            self.parts, self.verbose)
171 1
        builder.save_html(dict_oval_trees, src, rules)
172 1
        out_src.append(src)
173
174 1
    def open_html(self, out):
175 1
        for src in out:
176 1
            self.open_web_browser(src)
177
178 1
    def open_web_browser(self, src):
179 1
        if self.display_html:
180 1
            try:
181 1
                webbrowser.get('firefox').open_new_tab(src)
182
            except BaseException:
183
                webbrowser.open_new_tab(src)
184
185 1
    def _prepare_data(self, rules, dict_oval_trees, out_src):
186 1
        for rule in rules['rules']:
187 1
            try:
188 1
                self._put_to_dict_oval_trees(dict_oval_trees, rule)
189 1
                if not self.all_in_one:
190 1
                    self._build_and_save_html(
191
                        dict_oval_trees, self._get_src_for_one_graph(
192
                            rule), dict(
193
                            rules=[rule]), out_src)
194 1
                    dict_oval_trees = {}
195 1
            except NotChecked as error:
196
                self.print_red_text(error)
197 1
        if self.all_in_one:
198
            self._build_and_save_html(
199
                dict_oval_trees, self.get_save_src(
200
                    'rules' + self.date), rules, out_src)
201
202 1
    def prepare_data(self, rules):
203 1
        out_src = []
204 1
        oval_tree_dict = dict()
205 1
        self._prepare_data(rules, oval_tree_dict, out_src)
206 1
        self.open_html(out_src)
207 1
        return out_src
208
209 1
    def parse_arguments(self, args):
210 1
        self.prepare_parser()
211 1
        return self.parser.parse_args(args)
212
213 1
    def prepare_args_when_output_is_html(self):
214 1
        self.parser.add_argument(
215
            '-i',
216
            '--all-in-one',
217
            action="store_true",
218
            default=False,
219
            help="Processes all rules into one file.")
220 1
        self.parser.add_argument(
221
            '-d',
222
            '--display',
223
            action="store_true",
224
            default=False,
225
            help="Enables opening a web browser with a graph, when is used --output.")
226
227 1
    def prepare_args_when_user_can_list_in_rules(self):
228 1
        self.parser.add_argument(
229
            '--show-failed-rules',
230
            action="store_true",
231
            default=False,
232
            help="Show only FAILED rules")
233 1
        self.parser.add_argument(
234
            '--show-not-selected-rules',
235
            action="store_true",
236
            default=False,
237
            help="Show notselected rules. These rules will not be visualized.")
238
239 1
    def prepare_parser(self):
240 1
        self.parser = argparse.ArgumentParser(
241
            prog='oval-graph',
242
            description=self.MESSAGES.get('description'))
243 1
        self.parser.add_argument(
244
            '--version',
245
            action='version',
246
            version='%(prog)s ' + __version__)
247 1
        self.parser.add_argument(
248
            '-a',
249
            '--all',
250
            action="store_true",
251
            default=False,
252
            help="Process all matched rules.")
253 1
        self.parser.add_argument(
254
            '--hide-passing-tests',
255
            action="store_true",
256
            default=False,
257
            help=(
258
                "Do not display passing tests for better orientation in"
259
                " graphs that contain a large amount of nodes."))
260 1
        self.parser.add_argument(
261
            '-v',
262
            '--verbose',
263
            action="store_true",
264
            default=False,
265
            help="Displays details about the results of the running command.")
266 1
        self.parser.add_argument(
267
            '-o',
268
            '--output',
269
            action="store",
270
            default=None,
271
            help='The file where to save output.')
272 1
        self.parser.add_argument(
273
            "source_filename",
274
            help=self.MESSAGES.get('source_filename'))
275 1
        self.parser.add_argument(
276
            "rule_id", help=(
277
                "Rule ID to be visualized. A part from the full rule ID"
278
                " a part of the ID or a regular expression can be used."
279
                " If brackets are used in the regular expression "
280
                "the regular expression must be quoted."))
281