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

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

Complexity

Conditions 1

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 23
rs 9.0857
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
    def __init__(self,
13
                 executable=None,
14
                 executable_args="",
15
                 output_regex=None):
16
        """
17
        :param executable:      The executable to run the linter.
18
        :param executable_args: The arguments to supply to the linter, such
19
                                that the file name to be analyzed can be
20
                                appended to the end.
21
        :param output_regex:    The regex which will match the output of the
22
                                linter to get results. Thie regex should give
23
                                out the following variables:
24
                                 line - the line where the issue starts
25
                                 column - the column where the issue starts
26
                                 end_line - the line where the issue ends
27
                                 end_column - the column where the issue ends
28
                                 major - True is SEVERITY is MAJOR
29
                                 normal - True is SEVERITY is NORMAL
30
                                 message - The message of the result
31
        """
32
        self.executable = executable
33
        self.executable_args = executable_args
34
        self.output_regex = (output_regex or re.compile(
35
            r'(?P<line>\d+)\.(?P<column>\d+)\|'
36
            r'(?:(?P<major>[M])|(?P<normal>[N])|I)'
37
            r': (?P<message>.*)'))
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.executable_args + ' '
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
        stdout_file.seek(0)
57
        output = stdout_file.read().decode(sys.stdout.encoding,
58
                                           errors="replace")
59
        stdout_file.close()
60
        stderr_file.close()
61
        return self.process_output(output, filename)
62
63
    def process_output(self, output, filename):
64
        for match in re.finditer(self.output_regex, output):
65
            yield self.match_to_result(match, filename)
66
67
    def match_to_result(self, match, filename):
68
        """
69
        Converts a regex match's groups into a result.
70
71
        :param match:    The match got from regex parsing.
72
        :param filename: The name of the file from which this match is got.
73
        """
74
        groups = match.groupdict()
75
76
        # Attempt to convert all values from string to int as regex only
77
        # matches strings.
78
        for key, value in groups.items():
79
            try:
80
                value = int(value)
81
                groups[key] = value
82
            except (TypeError, ValueError):
83
                pass
84
85
        if groups.get("major") != None:
86
            severity = RESULT_SEVERITY.MAJOR
87
        elif groups.get("normal") != None:
88
            severity = RESULT_SEVERITY.NORMAL
89
        else:
90
            severity = RESULT_SEVERITY.INFO
91
92
        return Result.from_values(
93
            origin=self,
94
            message=groups.get("message", ""),
95
            file=filename,
96
            severity=severity,
97
            line=groups.get("line", 1),
98
            column=groups.get("column", 1),
99
            end_line=groups.get("end_line", None),
100
            end_column=groups.get("end_column", None))
101