Completed
Pull Request — master (#1109)
by Abdeali
02:49
created

coalib.bearlib.abstractions.Lint.lint()   B

Complexity

Conditions 2

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 2
dl 0
loc 28
rs 8.8571
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 output_stream: The stream (stderr or stdout) from which to take the
27
                          output.
28
    """
29
    executable = None
30
    arguments = ""
31
    output_regex = re.compile(r'(?P<line>\d+)\.(?P<column>\d+)\|'
32
                              r'(?P<severity>\d+): (?P<message>.*)')
33
    output_stream = "stdout"
34
35
    def lint(self, filename):
36
        """
37
        Takes a file and lints it using the linter variables defined apriori.
38
39
        :param filename: The name of the file to execute.
40
        """
41
        command = (self.executable + ' ' + self.arguments + ' '
42
                   + escape_path_argument(filename))
43
        stderr_file = tempfile.TemporaryFile()
44
        stdout_file = tempfile.TemporaryFile()
45
        process = subprocess.Popen(
46
            command,
47
            shell=True,
48
            stdout=stdout_file,
49
            stderr=stderr_file,
50
            universal_newlines=True)
51
        process.wait()
52
        if self.output_stream == "stderr":
53
            stderr_file.seek(0)
54
            output = stderr_file.read().decode(sys.stdout.encoding,
55
                                               errors="replace")
56
        else:
57
            stdout_file.seek(0)
58
            output = stdout_file.read().decode(sys.stdout.encoding,
59
                                               errors="replace")
60
        stdout_file.close()
61
        stderr_file.close()
62
        return self.process_output(output, filename)
63
64
    def process_output(self, output, filename):
65
        regex = self.output_regex
66
        if isinstance(regex, str):
67
            regex = regex % {"file_name": filename}
68
69
        for match in re.finditer(regex, output):
70
            yield self.match_to_result(match, filename)
71
72
    @staticmethod
73
    def _get_groupdict(match):
74
        groups = match.groupdict()
75
        # Attempt to convert all values from string to int as regex only
76
        # matches strings.
77
        for key, value in groups.items():
78
            try:
79
                value = int(value)
80
                groups[key] = value
81
            except (TypeError, ValueError):
82
                pass
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
        return Result.from_values(
95
            origin=self,
96
            message=groups.get("message", ""),
97
            file=filename,
98
            severity=groups.get("severity", RESULT_SEVERITY.NORMAL),
99
            line=groups.get("line"),
100
            column=groups.get("column", 0),
101
            end_line=groups.get("end_line", None),
102
            end_column=groups.get("end_column", None))
103