Passed
Push — master ( 73c0d2...e33474 )
by Matěj
01:54 queued 10s
created

oval_graph.client.Client._get_only_fail_rule()   A

Complexity

Conditions 2

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
nop 2
dl 0
loc 5
ccs 2
cts 2
cp 1
crap 2
rs 10
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
14
15 1
class Client():
16 1
    def __init__(self, args):
17 1
        self.parser = None
18 1
        self.MESSAGES = self._get_message()
19 1
        self.arg = self.parse_arguments(args)
20 1
        self.hide_passing_tests = self.arg.hide_passing_tests
21 1
        self.source_filename = self.arg.source_filename
22 1
        self.rule_name = self.arg.rule_id
23 1
        self.out = self.arg.output
24 1
        self.all_rules = self.arg.all
25 1
        self.all_in_one = None
26 1
        self.off_webbrowser = None
27 1
        self.isatty = sys.stdout.isatty()
28 1
        self.show_failed_rules = False
29 1
        self.show_not_selected_rules = False
30 1
        self.xml_parser = XmlParser(
31
            self.source_filename)
32 1
        self.parts = self.get_src('parts')
33
34 1
    def _get_message(self):
35 1
        MESSAGES = {
36
            'description': '',
37
            '--output': '',
38
            'source_filename': '',
39
        }
40 1
        return MESSAGES
41
42 1
    def print_red_text(self, text):
43
        CRED = '\033[91m'
44
        CEND = '\033[0m'
45
        print(CRED + str(text) + CEND)
46
47 1
    def run_gui_and_return_answers(self):
48 1
        if self.isatty:
49 1
            if self.all_rules:
50
                return self._get_rules()
51
            else:
52 1
                try:
53 1
                    import inquirer
54 1
                    return inquirer.prompt(self.get_questions())
55 1
                except ImportError:
56 1
                    print(self.get_selection_rules())
57 1
                    return None
58
        else:
59 1
            return self._get_rules()
60
61 1
    def _get_rules(self):
62 1
        if self.show_failed_rules:
63 1
            return {'rules': self._get_only_fail_rule(self.search_rules_id())}
64
        else:
65 1
            return {'rules': self.search_rules_id()}
66
67 1
    def get_list_of_matched_rules(self):
68 1
        rules = self.search_rules_id()
69 1
        if self.show_failed_rules:
70 1
            rules = self._get_only_fail_rule(rules)
71 1
        return rules
72
73 1
    def get_list_of_lines(self):
74 1
        lines = ['== The Rule IDs ==']
75 1
        for rule in self.get_list_of_matched_rules():
76 1
            lines.append("'" + rule + r'\b' + "'")
77 1
        if self.show_not_selected_rules:
78 1
            for line in self.get_lines_of_wanted_not_selected_rules():
79 1
                lines.append(line)
80 1
        lines.append(
81
            "You haven't got installed inquirer lib. "
82
            "Please copy id rule with you want use and put it in command")
83 1
        return lines
84
85 1
    def get_selection_rules(self):
86 1
        return "\n".join(self.get_list_of_lines())
87
88 1
    def get_lines_of_wanted_not_selected_rules(self):
89 1
        out = []
90 1
        out.append('== The not selected rule IDs ==')
91 1
        for rule in self._get_wanted_rules_from_array_of_IDs(
92
                self.xml_parser.notselected_rules):
93 1
            out.append(rule + '(Not selected)')
94 1
        return out
95
96 1
    def get_choices(self):
97 1
        rules = self.search_rules_id()
98 1
        if self.show_failed_rules:
99 1
            rules = self._get_only_fail_rule(rules)
100 1
        choices = rules
101 1
        if self.show_not_selected_rules:
102 1
            print("\n".join(self.get_lines_of_wanted_not_selected_rules()))
103 1
        return choices
104
105 1
    def get_questions(self):
106 1
        choices = self.get_choices()
107 1
        from inquirer.questions import Checkbox as checkbox
108 1
        questions = [
109
            checkbox(
110
                'rules',
111
                message=(
112
                    "= The Rules IDs = (move - UP and DOWN arrows,"
113
                    " select - SPACE or LEFT and RIGHT arrows, submit - ENTER)"),
114
                choices=choices,
115
            ),
116
        ]
117 1
        return questions
118
119 1
    def _get_only_fail_rule(self, rules):
120 1
        return list(
121
            filter(
122
                lambda rule: self.xml_parser.used_rules[rule]['result'] == 'fail',
123
                rules))
124
125 1
    def _get_wanted_rules_from_array_of_IDs(self, rules):
126 1
        return [
127
            x for x in rules if re.search(
128
                self.rule_name, x)]
129
130 1
    def search_rules_id(self):
131 1
        rules = self._get_wanted_rules_from_array_of_IDs(
132
            self.xml_parser.used_rules.keys())
133 1
        notselected_rules = self._get_wanted_rules_from_array_of_IDs(
134
            self.xml_parser.notselected_rules)
135 1
        return self._check_rules_id(rules, notselected_rules)
136
137 1
    def _check_rules_id(self, rules, notselected_rules):
138 1
        if len(notselected_rules) and not rules:
139 1
            raise ValueError(
140
                ('Rule(s) "{}" was not selected, '
141
                 "so there are no results. The rule is"
142
                 ' "notselected" because it'
143
                 " wasn't a part of the executed profile"
144
                 " and therefore it wasn't evaluated "
145
                 "during the scan.")
146
                .format(notselected_rules))
147 1
        elif not notselected_rules and not rules:
148 1
            raise ValueError('404 rule "{}" not found!'.format(self.rule_name))
149
        else:
150 1
            return rules
151
152 1
    def save_html_and_open_html(self, oval_tree_dict, src, rule, out):
153 1
        self.save_html_report(oval_tree_dict, src)
154 1
        self.print_output_message_and_open_web_browser(src, rule, out)
155
156 1
    def save_html_with_all_rules_in_one(
157
            self, dict_oval_trees, src, rules, out):
158
        self.save_html_report(dict_oval_trees, src, self.all_in_one)
159
        self.print_output_message_and_open_web_browser(
160
            src, self._format_rules_output(rules), out)
161
162 1
    def _format_rules_output(self, rules):
163
        out = ''
164
        for rule in rules['rules']:
165
            out += rule + '\n'
166
        return out
167
168 1
    def print_output_message_and_open_web_browser(self, src, rule, out):
169 1
        print('Rule(s) "{}" done!'.format(rule))
170 1
        out.append(src)
171 1
        self.open_web_browser(src)
172
173 1
    def open_web_browser(self, src):
174 1
        if not self.off_webbrowser:
175
            try:
176
                webbrowser.get('firefox').open_new_tab(src)
177
            except BaseException:
178
                webbrowser.open_new_tab(src)
179
180 1
    def get_src(self, src):
181 1
        _dir = os.path.dirname(os.path.realpath(__file__))
182 1
        FIXTURE_DIR = os.path.join(_dir, src)
183 1
        return str(FIXTURE_DIR)
184
185 1
    def _prepare_all_in_one_data(self, rules, dict_oval_trees, out, date=None):
186
        for rule in rules['rules']:
187
            try:
188
                self._put_to_dict_oval_trees(dict_oval_trees, rule, date)
189
            except NotChecked as error:
190
                self.print_red_text(error)
191
        src = self.get_save_src('rules')
192
        self.save_html_with_all_rules_in_one(
193
            dict_oval_trees, src, rules, out)
194
        return out
195
196 1
    def _prepare_data_by_one(self, rules, dict_oval_trees, out, date=None):
197 1
        for rule in rules['rules']:
198 1
            try:
199 1
                oval_tree_dict = self.create_dict_of_rule(rule)
200 1
                src = self._get_src_for_one_graph(rule, date)
201 1
                self.save_html_and_open_html(
202
                    oval_tree_dict, src, rule, out)
203 1
            except NotChecked as error:
204
                self.print_red_text(error)
205 1
        return out
206
207 1
    def get_save_src(self, rule):
208 1
        if self.out is not None:
209 1
            os.makedirs(self.out, exist_ok=True)
210 1
            return os.path.join(
211
                self.out,
212
                'graph-of-' + rule + '.html')
213 1
        return os.path.join(
214
            os.getcwd(),
215
            'graph-of-' + rule + '.html')
216
217 1
    def _get_part(self, part):
218 1
        with open(os.path.join(self.parts, part), "r") as data_file:
219 1
            return data_file.readlines()
220
221 1
    def _merge_report_parts(self, data):
222 1
        head = self._get_part('head.txt')
223 1
        css = self._get_part('css.txt')
224 1
        boot_strap_style = self._get_part('bootstrapStyle.txt')
225 1
        jsTree_style = self._get_part('jsTreeStyle.txt')
226 1
        jQuery_script = self._get_part('jQueryScript.txt')
227 1
        boot_strap_script = self._get_part('bootstrapScript.txt')
228 1
        jsTree_script = self._get_part('jsTreeScript.txt')
229 1
        body_start = ['</head>', '<body>', data]
230 1
        body = self._get_part('body.txt')
231 1
        script = self._get_part('script.js')
232 1
        footer = ['<script>', *script, '</script>', '</body>', '</html>']
233 1
        return [
234
            *head,
235
            *css,
236
            *boot_strap_style,
237
            *jsTree_style,
238
            *jQuery_script,
239
            *boot_strap_script,
240
            *jsTree_script,
241
            *body_start,
242
            *body,
243
            *footer]
244
245 1
    def save_html_report(self, dict_, src, status_all_in_one=False):
246 1
        data = ("\n<script>var all_in_one = " +
247
                str(status_all_in_one).lower() +
248
                ";</script>" +
249
                "\n<script>var data_of_tree =" +
250
                str(json.dumps(dict_, sort_keys=False, indent=4)) +
251
                ";</script>\n")
252 1
        if status_all_in_one:
253
            for rule in dict_:
254
                data += ('<h1>' +
255
                         rule.split('-')[2] +
256
                         '</h1>' +
257
                         '<div id="' +
258
                         re.sub(r'[\_\-\.]', "", rule) +
259
                         '"></div>')
260 1
        with open(src, "w+") as data_file:
261 1
            data_file.writelines(self._merge_report_parts(data))
262
263 1
    def parse_arguments(self, args):
264 1
        self.prepare_parser()
265 1
        args = self.parser.parse_args(args)
266 1
        return args
267
268 1
    def prepare_parser(self):
269 1
        self.parser = argparse.ArgumentParser(
270
            description=self.MESSAGES.get('description'))
271 1
        self.parser.add_argument(
272
            '--all',
273
            action="store_true",
274
            default=False,
275
            help="Process all matched rules.")
276 1
        self.parser.add_argument(
277
            '--hide-passing-tests',
278
            action="store_true",
279
            default=False,
280
            help=(
281
                "Do not display passing tests for better orientation in"
282
                " graphs that contain a large amount of nodes.(Not implemented)"))
283 1
        self.parser.add_argument(
284
            '-o',
285
            '--output',
286
            action="store",
287
            default=None,
288
            help=self.MESSAGES.get('--output'))
289 1
        self.parser.add_argument(
290
            "source_filename",
291
            help=self.MESSAGES.get('source_filename'))
292 1
        self.parser.add_argument(
293
            "rule_id", help=(
294
                "Rule ID to be visualized. A part from the full rule ID"
295
                " a part of the ID or a regular expression can be used."
296
                " If brackets are used in the regular expression "
297
                "the regular expression must be quoted."))
298