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

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

Complexity

Conditions 3

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 3
dl 0
loc 7
rs 9.4286
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:   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
    use_stderr = False
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.use_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
        return groups
76
77
    def match_to_result(self, match, filename):
78
        """
79
        Converts a regex match's groups into a result.
80
81
        :param match:    The match got from regex parsing.
82
        :param filename: The name of the file from which this match is got.
83
        """
84
        groups = self._get_groupdict(match)
85
86
        # Pre process the groups
87
        end_line = groups.get("end_line", None)
88
        if end_line != None:
89
            end_line = int(end_line)
90
        end_column = groups.get("end_column", None)
91
        if end_column != None:
92
            end_column = int(end_column)
93
94
        return Result.from_values(
95
            origin=self,
96
            message=groups.get("message", ""),
97
            file=filename,
98
            severity=int(groups.get("severity", RESULT_SEVERITY.NORMAL)),
99
            line=int(groups.get("line")),
100
            column=int(groups.get("column", 0)),
101
            end_line=end_line,
102
            end_column=end_column)
103