Completed
Pull Request — master (#1109)
by Abdeali
01:53
created

coalib.bearlib.abstractions.Lint._get_groupdict()   A

Complexity

Conditions 4

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 4
dl 0
loc 8
rs 9.2
1
import subprocess
2
import tempfile
3
import re
4
import sys
5
6
from coalib.misc.Shell import escape_path_argument
7
from coalib.results.Result import Result
8
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY
9
10
11
class Lint():
12
    """
13
    :param executable:   The executable to run the linter.
14
    :param arguments:    The arguments to supply to the linter, such
15
                         that the file name to be analyzed can be
16
                         appended to the end.
17
    :param output_regex: The regex which will match the output of the linter
18
                         to get results. Thie regex should give out the
19
                         following variables:
20
                          line - The line where the issue starts.
21
                          column - The column where the issue starts.
22
                          end_line - The line where the issue ends.
23
                          end_column - The column where the issue ends.
24
                          severity - The severity of the issue.
25
                          message - The message of the result.
26
    :param use_stderr:   Uses stderr as the output stream is it's True.
27
    :param severity_map: A dict where the keys are the possible severity
28
                         values the Linter gives out and the values are the
29
                         severity of the coala Result to set it to. If it is
30
                         not a dict, it is ignored.
31
    """
32
    executable = None
33
    arguments = ""
34
    output_regex = re.compile(r'(?P<line>\d+)\.(?P<column>\d+)\|'
35
                              r'(?P<severity>\d+): (?P<message>.*)')
36
    use_stderr = False
37
    severity_map = None
38
39
    def lint(self, filename):
40
        """
41
        Takes a file and lints it using the linter variables defined apriori.
42
43
        :param filename: The name of the file to execute.
44
        """
45
        command = (self.executable + ' ' + self.arguments + ' '
46
                   + escape_path_argument(filename))
47
        stderr_file = tempfile.TemporaryFile()
48
        stdout_file = tempfile.TemporaryFile()
49
        process = subprocess.Popen(
50
            command,
51
            shell=True,
52
            stdout=stdout_file,
53
            stderr=stderr_file,
54
            universal_newlines=True)
55
        process.wait()
56
        if self.use_stderr:
57
            stderr_file.seek(0)
58
            output = stderr_file.read().decode(sys.stdout.encoding,
59
                                               errors="replace")
60
        else:
61
            stdout_file.seek(0)
62
            output = stdout_file.read().decode(sys.stdout.encoding,
63
                                               errors="replace")
64
        stdout_file.close()
65
        stderr_file.close()
66
        return self.process_output(output, filename)
67
68
    def process_output(self, output, filename):
69
        regex = self.output_regex
70
        if isinstance(regex, str):
71
            regex = regex % {"file_name": filename}
72
73
        for match in re.finditer(regex, output):
74
            yield self.match_to_result(match, filename)
75
76
    def _get_groupdict(self, match):
77
        groups = match.groupdict()
78
        if (
79
                isinstance(self.severity_map, dict) and
80
                "severity" in groups and
81
                groups["severity"] in self.severity_map):
82
            groups["severity"] = self.severity_map[groups["severity"]]
83
        return groups
84
85
    def match_to_result(self, match, filename):
86
        """
87
        Converts a regex match's groups into a result.
88
89
        :param match:    The match got from regex parsing.
90
        :param filename: The name of the file from which this match is got.
91
        """
92
        groups = self._get_groupdict(match)
93
94
        # Pre process the groups
95
        end_line = groups.get("end_line", None)
96
        if end_line != None:
97
            end_line = int(end_line)
98
        end_column = groups.get("end_column", None)
99
        if end_column != None:
100
            end_column = int(end_column)
101
102
        return Result.from_values(
103
            origin=self,
104
            message=groups.get("message", ""),
105
            file=filename,
106
            severity=int(groups.get("severity", RESULT_SEVERITY.NORMAL)),
107
            line=int(groups.get("line")),
108
            column=int(groups.get("column", 0)),
109
            end_line=end_line,
110
            end_column=end_column)
111